Перейти к содержанию
    

STM32g474 Bootloader через I2c

Добрый день.

Я пытаюсь достучаться до встроенного загрузчика через другой микроконтроллер по протоколу I2C.

RST выставляю в 0, BOOT0 в 1 и отпускаю RST

//i2c 100kHz
 
HAL_StatusTypeDef status;
 
uint8_t tmp[2];
uint8_t dat[21];
uint8_t ACK;
 
	while(HAL_I2C_GetState(I2cHandle) != HAL_I2C_STATE_READY);
	status = HAL_I2C_Master_Transmit_IT(I2cHandle, 0xa6, dat, 1);
	while (HAL_I2C_GetState(I2cHandle) != HAL_I2C_STATE_READY) ;
	status = HAL_I2C_Master_Receive_IT(I2cHandle, 0xa6, &ACK, 1);
while(1)
	{
		tmp[0] = 1;//Get Version command
		tmp[1] = 0xfe;//XOR tmp[0]
		while (HAL_I2C_GetState(I2cHandle) != HAL_I2C_STATE_READY) ;
		status = HAL_I2C_Master_Transmit_IT(I2cHandle, 0xa6, tmp, 2);
		memset(dat, 0, sizeof(dat));
		while (HAL_I2C_GetState(I2cHandle) != HAL_I2C_STATE_READY) ;
		status = HAL_I2C_Master_Receive_IT(I2cHandle, 0xa6, &ACK, 1);
		if (ACK == 0x79)
		{			
			while (HAL_I2C_GetState(I2cHandle) != HAL_I2C_STATE_READY) ;
			status = HAL_I2C_Master_Receive_IT(I2cHandle, 0xa6, dat, 2);	
//Практически всегда получаю нули. Иногда приходит 0x12 0xff
		}
		else if (ACK == 0x1f)//nack
		{
//Иногда попадаю сюда
		}
		else if(ACK == 0x76)//busy
		{
		}
			else
		{
		}
}

В документе AN2606 слэйв адрес указан 0b1010100x. У меня получилось достучаться только по адресу 0b1010011x. Это ошибка документации?

В AN4221 очень мало информации по протоколу.

По коду, что выше, слэйв часто притягивает линию SCL до 10 секунд.

ACK (0x76) получаю, иногда  NACK. 

В ответ в массиве нули. Иногда проскакивает 0x12 0xff

Как правильно работать с бутом по этому протоколу?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Разобрался как принимать байты. Загрузчик работает только побайтно

if (ACK == 0x79)
		{			
			status = HAL_I2C_Master_Receive_IT(I2cHandle, 0xa6, &dat[0], 1);
//https://www.st.com/resource/en/application_note/dm00072315-i2c-protocol-used-in-the-stm32-bootloader-stmicroelectronics.pdf
//page 11
//Byte 2: Bootloader version (0 < Version ≤ 255) (for example, 0x10 = Version 1.0)
                        while (HAL_I2C_GetState(I2cHandle) != HAL_I2C_STATE_READY) ;
                        status = HAL_I2C_Master_Receive_IT(I2cHandle, 0xa6, &dat[1], 1);	
//Byte 3: ACK
                        while (HAL_I2C_GetState(I2cHandle) != HAL_I2C_STATE_READY) ;
		}

Пропали залипания линии SCL и начали приходить адекватные ответы

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Привожу код, который заработал. Из-за дурацкой документации AN4221, пришлось повозиться и поподбирать последовательность команд

#define GET_CMD_COMMAND        0x00U  /*!< Get CMD command               */
#define GET_VER_COMMAND        0x01U  /*!< Get Version command           */
#define GET_ID_COMMAND         0x02U  /*!< Get ID command                */
#define RMEM_COMMAND           0x11U  /*!< Read Memory command           */
#define GO_COMMAND             0x21U  /*!< Go command                    */
#define WMEM_COMMAND           0x31U  /*!< Write Memory command          */
#define EMEM_COMMAND           0x44U  /*!< Erase Memory command          */
#define WP_COMMAND             0x63U  /*!< Write Protect command         */
#define WU_COMMAND             0x73U  /*!< Write Unprotect command       */
#define RP_COMMAND             0x82U  /*!< Readout Protect command       */
#define RU_COMMAND             0x92U  /*!< Readout Unprotect command     */
 
I2C_HandleTypeDef *I2cHandle;
 
void BL_Init(I2C_HandleTypeDef *hi2c)
{
	I2cHandle = hi2c;
}
 
HAL_StatusTypeDef BL_Transmit(uint8_t *pDat, uint16_t num)
{
	HAL_StatusTypeDef status;
	while (HAL_I2C_GetState(I2cHandle) != HAL_I2C_STATE_READY) ;
	status = HAL_I2C_Master_Transmit_IT(I2cHandle, 0xa6, pDat, num);
	while (HAL_I2C_GetState(I2cHandle) != HAL_I2C_STATE_READY) ;
	return status;
}
 
HAL_StatusTypeDef BL_Receive(uint8_t *pDat, uint16_t num)
{
	HAL_StatusTypeDef status;
	while (HAL_I2C_GetState(I2cHandle) != HAL_I2C_STATE_READY) ;
	status = HAL_I2C_Master_Receive_IT(I2cHandle, 0xa6, pDat, num);
	while (HAL_I2C_GetState(I2cHandle) != HAL_I2C_STATE_READY) ;
	return status;
}
 
uint8_t BL_GetVersion(void)
{
	HAL_StatusTypeDef status;
	uint8_t ACK;
	uint8_t cmd_frame[2];
	uint8_t version = 0x00U;
 
	cmd_frame[0] = GET_VER_COMMAND;
	cmd_frame[1] = GET_VER_COMMAND ^ 0xFFU;
	status = BL_Transmit(cmd_frame, 2);
	status = BL_Receive(&ACK, 1);
	if (ACK == 0x79)
	{			
		status = BL_Receive(&version, 1);
		status = BL_Receive(&ACK, 1);
		if (ACK == 0x79) return version;
	}
	return 0xff;
}
 
HAL_StatusTypeDef BL_ReadMemory(uint32_t address, uint16_t nob, uint8_t *pData)
{
	HAL_StatusTypeDef status;
	uint8_t ACK;
	uint8_t frame[5];
 
	frame[0] = RMEM_COMMAND;
	frame[1] = RMEM_COMMAND ^ 0xFFU;
	status = BL_Transmit(frame, 2);
	status = BL_Receive(&ACK, 1);
	if (ACK == 0x79)
	{			
		frame[0] = (uint8_t)((address >> 24) & 0xFFU);
		frame[1] = (uint8_t)((address >> 16) & 0xFFU);
		frame[2] = (uint8_t)((address >> 8) & 0xFFU);
		frame[3] = (uint8_t)(address & 0xFFU);
		frame[4] = xor_checksum(frame, 4U);
		status = BL_Transmit(frame, 5);
		ACK = 0;
		status = BL_Receive(&ACK, 1);
		if (ACK == 0x79)
		{
			frame[0] = (nob - 1U);
			frame[1] = (nob - 1U) ^ 0xFFU;
			status = BL_Transmit(frame, 2);
			ACK = 0;
			status = BL_Receive(&ACK, 1);
			if (ACK == 0x79)
			{
				status = BL_Receive(pData, nob);//data+ack
				ACK = 0;
			}
			else return HAL_ERROR;
		}
		else return HAL_ERROR;
	}
	else return HAL_ERROR;
	return HAL_OK;
}
 
HAL_StatusTypeDef BL_WriteMemory(uint32_t address, uint16_t nob, uint8_t *pData)
{
	HAL_StatusTypeDef status;
	uint8_t ACK=0;
	uint8_t frame[258];
	uint8_t checksum = xor_checksum(pData, nob) ^ (nob - 1U );
 
	frame[0] = WMEM_COMMAND;
	frame[1] = WMEM_COMMAND ^ 0xFFU;
	status = BL_Transmit(frame, 2);
	ACK = 0;
	status = BL_Receive(&ACK, 1);
	if (ACK == 0x79)
	{
		frame[0] = ((uint8_t)(address >> 24) & 0xFFU);
		frame[1] = ((uint8_t)(address >> 16) & 0xFFU);
		frame[2] = ((uint8_t)(address >> 8) & 0xFFU);
		frame[3] = ((uint8_t) address & 0xFFU);
		frame[4] = xor_checksum(frame, 4U);
		status = BL_Transmit(frame, 5);
		ACK = 0;
		status = BL_Receive(&ACK, 1);
		if (ACK == 0x79)
		{
			frame[0] = nob - 1U;
			memcpy(&frame[1], pData, nob);
			frame[nob + 1] = checksum;
			status = BL_Transmit(frame, (uint16_t) nob + 2);
			status = BL_Receive(&ACK, 1);
		}
		else return HAL_ERROR;
	}
	else return HAL_ERROR;
	return HAL_OK;
}
 
HAL_StatusTypeDef BL_EraseMemory(uint16_t nb, uint8_t code)
{
	HAL_StatusTypeDef status;
	uint8_t ACK;	
	uint8_t frame[3];
 
	frame[0] = EMEM_COMMAND;
	frame[1] = EMEM_COMMAND ^ 0xFFU;
	status = BL_Transmit(frame, 2);
	status = BL_Receive(&ACK, 1);
	if (ACK == 0x79)
	{
		frame[0] = (uint8_t)(nb >> 8) & 0xFFU;
		frame[1] = (uint8_t) nb & 0xFFU;
		frame[2] = frame[0] ^ frame[1];
		status = BL_Transmit(frame, 3);
		status = BL_Receive(&ACK, 1);
		if (ACK == 0x79)
		{
			if ((nb >> 4) != 0xFFF)
			{
				frame[0] = (uint8_t)(code >> 8) & 0xFFU;
				frame[1] = code & 0xFFU;
				frame[2] = frame[0] ^ frame[1];
				status = BL_Transmit(frame, 3);
				status = BL_Receive(&ACK, 1);
			}
		}
		else return HAL_ERROR;
	}
	else return HAL_ERROR;
	return HAL_OK;
 
}
 
static uint8_t xor_checksum(const uint8_t pData[], uint16_t len)
{
	uint8_t sum = *pData;
	for (uint16_t i = 1U; i < len; i++)
		sum ^= pData[i];
	return sum;
}

В кубе в i2c не забыть поставить галочки на прерываниях.

Код для тестирования

uint8_t trsmt[256];
uint8_t recv[257];//add ack
HAL_StatusTypeDef status;
uint8_t tmp;
 
for (uint16_t i = 0; i < 256; i++)
		trsmt[i] = i;
 	BL_Init(&hi2c2);
	
	while (1)
	{
		
		tmp = BL_GetVersion();
		status = BL_EraseMemory(0xffff, 1);
		tmp = 0;
		tmp = BL_GetVersion();
		status = BL_ReadMemory(0x08000000, 256, recv);
		tmp = 0;
		tmp = BL_GetVersion();
		status = BL_WriteMemory(0x08000000, 256, trsmt);
		tmp = 0;
		tmp = BL_GetVersion();
		status = BL_ReadMemory(0x08000000, 256, recv);
	}

 

ps. Допилил http server на основном контроллере, теперь 4 слэйва обновляю через вебморду. Мастер обновляю через http IAP Bootloader )))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...