2020-06-05 02:01 AM
Good afternoon.
I am trying to program STM32G47X through the built-in bootloader using a protocol I2C from another microcontroller.
Document 2606 on page 212 indicates the slave address 0b1010100x. I managed to get through only at 0b1010011x. Is this a bug in the documentation?
Document 4221 also has very little information. I enter bootloader mode by setting boot1 to 1 and releasing the reset.
//i2c 100kHz
HAL_StatusTypeDef status;
uint8_t tmp[2];
uint8_t dat[21];
uint8_t ACK;
while(HAL_I2C_GetState(hi2c) != HAL_I2C_STATE_READY);
status = HAL_I2C_Master_Transmit_IT(I2cHandle, 0xa6, dat, 1);
while (HAL_I2C_GetState(hi2c) != HAL_I2C_STATE_READY) ;
status = HAL_I2C_Master_Receive_IT(I2cHandle, 0xa7, &ACK, 1);
while(1)
{
tmp[0] = 1;
tmp[1] = 0xfe;//XOR tmp[0]
while (HAL_I2C_GetState(hi2c) != HAL_I2C_STATE_READY) ;
status = HAL_I2C_Master_Transmit_IT(I2cHandle, 0xa6, tmp, 2);
memset(dat, 0, sizeof(dat));
while (HAL_I2C_GetState(hi2c) != HAL_I2C_STATE_READY) ;
status = HAL_I2C_Master_Receive_IT(I2cHandle, 0xa7, &ACK, 1);
if (ACK == 0x79)
{
while (HAL_I2C_GetState(hi2c) != HAL_I2C_STATE_READY) ;
status = HAL_I2C_Master_Receive_IT(I2cHandle, 0xa7, dat, 2);
//I accept only zeros!
}
else if (ACK == 0x1f)//nack
{
//Sometimes I get here
}
else if(ACK == 0x76)//busy
{
}
else
{
}
Often, the slave controller presses the SCL line to the ground. And you have to wait up to 10 seconds.
Maybe someone has an example working?
I don’t understand how to receive data after the response ACK == 0x79
2020-06-05 04:31 PM
If you want to use I2C in blocking mode, use HAL_I2C_Master_Transmit instead of HAL_I2C_Master_Transmit_IT. The latter transfers asynchronously and you need to wait for completion before accessing the data. Which you do in most places, but not all.
> I don’t understand how to receive data after the response ACK == 0x79
Not sure what you mean. You receive data with HAL_I2C_Master_Receive.
From the app note:
Note: The host frame can be one of the following:
• Send Command frame: The host initiates communication as master transmitter, and sends two bytes to the device: command code + XOR.
• Wait for ACK/NACK frame: The host initiates an I2C communication as master receiver, and receives one byte from the device: ACK or NACK or BUSY.
• Receive Data frame: The host initiates an I2C communication as master receiver, and receives the response from the device. The number of received bytes depends on the command.
• Send Data frame: The host initiates an I2C communication as master transmitter, and sends the needed bytes to the device. The number of transmitted bytes depends on the command.
2020-06-09 02:42 PM
It seems to figure it out. The loader sends data by one byte
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) ;
}
2020-06-11 10:31 AM
Everything worked. I bring the code.
#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 ***, 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] = (*** - 1U);
frame[1] = (*** - 1U) ^ 0xFFU;
status = BL_Transmit(frame, 2);
ACK = 0;
status = BL_Receive(&ACK, 1);
if (ACK == 0x79)
{
status = BL_Receive(pData, ***);//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 ***, uint8_t *pData)
{
HAL_StatusTypeDef status;
uint8_t ACK=0;
uint8_t frame[258];
uint8_t checksum = xor_checksum(pData, ***) ^ (*** - 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] = *** - 1U;
memcpy(&frame[1], pData, ***);
frame[*** + 1] = checksum;
status = BL_Transmit(frame, (uint16_t) *** + 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[], uint8_t len)
{
uint8_t sum = *pData;
for (uint8_t i = 1U; i < len; i++)
sum ^= pData[i];
return sum;
}
don't forget in the cube in i2c to tick off interrupts.
code for testing
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);
}