GD32设置i2c从机模式的IAP升级
1、gd32的I2C从机设置
关于i2c从机的设置在17节讲过,这里我们就在17节的基础上将i2c1设置为从机模式,七位从机地址为0x18.
2、升级协议
同上一节的协议,只是每包发送的数据变成了64 个,
/*串口升级协议如下:
cmd + data length + data0 + ....+ data_n + checksum
1、获取版本号 0x01 0x02 0x00 0x00 checksum
2、升级
1、进入升级模式 0x02 0x02 0x00 0x00 checksum
2、升级文件大小 0x03 0x04 0x00 0x00 0x00 0x00 checksum
3、数据包发送 0x04 0x40 0x00 0x00 0x00 0x00 ..... checksum
4、数据包发送完成 0x05 0x02 0x00 0x00 checksum
*/
3、gd32代码添加
a、获取版本号:
MI_BOOL send_i2c_message(MI_U8 *p_buff,MI_U32 len)
{
switch (p_buff[UART_CMD_INDEX])
{
case I2C_GET_SYSTEM_VERSION_CMD/* constant-expression */:
/* 获取系统版本号 */
if (calculate_checksum_and_length(p_buff,len) == MI_TRUE)
{
char version[28] = {0};
sprintf(version,"%s %s",APPCATION_VERSION_DATE,APPCATION_VERSION_TIME);
memset(i2c_txbuffer,0,128);
memcpy(i2c_txbuffer,version,strlen(version));
printf("get version = %s\r\n",version);
}
break;
default:
break;
}
return MI_TRUE;
}
这里的i2c_txbuffer通过i2c回调函数发送出去。
b、升级相关代码处理。
MI_BOOL handle_i2c_message(MI_U8 *p_buff,MI_U32 len)
{
switch (p_buff[I2C_CMD_INDEX])
{
case I2C_GET_SYSTEM_VERSION_CMD/* constant-expression */:
/* 获取系统版本号 */
/* Noting to do send_i2c_message 中处理*/
break;
case I2C_ENTER_SYSTEM_UPDATE_MODE_CMD:
/* 进入升级模式命令 指示灯变为100ms闪烁一次*/
if (calculate_checksum_and_length(p_buff,len) == MI_TRUE)
{
led_freq = 100;
w_time = 0;
packets_numer = 0;
upgrade_file_size = 0;
remain_packets_numer = 0;
isRunningUpdate = 1;
printf("Mcu Receive Update Command and Wait Receive Data Packets \r\n");
printf("Now to Erase Download Pages \r\n");
printf("\r\n");
gd32_flash_erase(DOWNLOAD_START_ADDRESS,DOWNLOAD_END_ADDRESS);
printf("\r\n");
}
break;
case I2C_GET_SYSTEM_FILE_SIZE_CMD:
if (calculate_checksum_and_length(p_buff,len) == MI_TRUE)
{
int a = (int)p_buff[2];
int b = (int)p_buff[3];
int c = (int)p_buff[4];
int d = (int)p_buff[5];
upgrade_file_size = (a<<24) | (b<<16) | (c<<8) | (d);
if (upgrade_file_size % I2C_UPGRADE_DATA_PACKAGES_LENGHT == 0) //如果整除128
{
packets_numer = upgrade_file_size/I2C_UPGRADE_DATA_PACKAGES_LENGHT;
}
else
{
packets_numer = ((upgrade_file_size/I2C_UPGRADE_DATA_PACKAGES_LENGHT) + 1);
}
printf("End Erase Download Pages DONE!!\r\n");
printf("\r\n");
printf("receive upgrade file size %d\r\n",upgrade_file_size);
printf("data packets number %d\r\n",packets_numer);
printf("\r\n");
}
break;
case I2C_RECEIVE_SYSTEM_UPDATE_CMD:
if (calculate_checksum_and_length(p_buff,len) == MI_TRUE)
{
printf("receive packets........................%03d [100] \r\n",(((w_time + 1) * 100) / packets_numer));
memset(i2c_w_buff,0,sizeof(i2c_w_buff));
memcpy(i2c_w_buff,&p_buff[2],sizeof(i2c_w_buff));
gd32_flash_write(DOWNLOAD_START_ADDRESS+(w_time * I2C_UPGRADE_DATA_PACKAGES_LENGHT),i2c_w_buff,sizeof(i2c_w_buff));
if (w_time + 1 == packets_numer)
{
led_freq = 500;
printf("receive packets........................ done!\r\n");
}
w_time ++;
}
break;
case I2C_COMPLETE_SYSTEM_UPDATE_CMD:
if (calculate_checksum_and_length(p_buff,len) == MI_TRUE)
{
system_info_set_update_flag(1);
printf("Now Reboot !\r\n");
app_soft_reset();
}
break;
default:break;
}
#if DEBUG
if(p_buff != 0)
{
for(int i=0;i<len;i++)
{
printf("0x%02x " ,p_buff[i]);
}
printf("\r\n");
}
#endif
return MI_TRUE;
}
整体逻辑同蓝牙串口模块升级类似,只不过i2c是通过树莓派作为i2c主设备来升级的。
树莓升级代码
#include <sys/ioctl.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <strings.h> /* for strcasecmp() */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <dirent.h>
#include <fcntl.h>
#include <errno.h>
#define APPLICATION_PATH "Application.bin"
#define UPGRADE_DATA_PACKAGES_LENGHT 0x40
#define UPGRADE_PACKAGES_LENGHT 0x40 + 0x04
typedef enum{
MI_FALSE = 0,
MI_TRUE = 1,
}MI_BOOL;
typedef unsigned char MI_U8;
typedef unsigned short MI_U16;
static int i2c_write(int fd,int slave_addr,unsigned char *p_data,unsigned short len);
static int i2c_read(int fd,int slave_addr,unsigned char *w_data,
unsigned short w_len,unsigned char *p_data,unsigned short len);
MI_U8 get_ver_cmd[6] = {0x01,0x02,0x00,0x00,0x00,0x00};
MI_U8 update_cmd[6] = {0x02,0x02,0x00,0x00,0x00,0x00};
MI_U8 file_size_cmd[8] = {0x03,0x04,0x00,0x00,0x00,0x00,0x00,0x00};
MI_U8 file_package[UPGRADE_PACKAGES_LENGHT] = {0x04,UPGRADE_DATA_PACKAGES_LENGHT};
MI_U8 update_complete_cmd[6] = {0x05,0x02,0x00,0x00};
MI_U16 w_num = 0;
char r_data[256] = {0};
#define I2C_DATA_LENGTH_MAX 132
#define MISSING_FUNC_FMT "Error: Adapter does not have %s capability\n"
static MI_BOOL get_update_file_size(char * file_path,size_t *size)
{
FILE *file;
file = fopen(file_path,"rb");
if (!file)
{
perror("get_update_file_size fopen error\n");
return MI_FALSE;
}
fseek(file, 0L, SEEK_END);
*size = ftell(file);
fclose(file);
return MI_TRUE;
}
static MI_U16 CRC16(MI_U8 * buf, MI_U16 len)
{
MI_U16 i;
MI_U16 crc = 0xffff;
if (len == 0) {
len = 1;
}
while (len--) {
crc ^= *buf;
for (i = 0; i<8; i++)
{
if (crc & 1) {
crc >>= 1;
crc ^= 0xA001;
}
else {
crc >>= 1;
}
}
buf++;
}
return(crc);
}
static MI_BOOL compare(MI_U8 *des,MI_U8 *src,int len)
{
while (len--)
{
if (*des != *src)
{
return MI_FALSE;
}
des++;
src++;
}
return MI_TRUE;
}
static void send_get_version_cmd(int fd,MI_U8 *p_data,MI_U16 r_len)
{
int len = sizeof(get_ver_cmd);
int crc = CRC16(get_ver_cmd,len-2);
get_ver_cmd[len-2] = crc & 0x00ff;
get_ver_cmd[len-1] = ((crc >> 8) & 0x00ff);
i2c_read(fd,0x18,get_ver_cmd,len,p_data,r_len);
}
static void send_enter_update_cmd(int fd)
{
int len = sizeof(update_cmd);
int crc = CRC16(update_cmd,len-2);
update_cmd[len-2] = crc & 0x00ff;
update_cmd[len-1] = ((crc >> 8) & 0x00ff);
i2c_write(fd,0x18,update_cmd,len);
}
static MI_BOOL send_update_file_size_cmd(int fd)
{
int len = sizeof(file_size_cmd);
size_t file_size = 0;
get_update_file_size(APPLICATION_PATH,&file_size);
file_size_cmd[2] = (file_size >> 24 & (0xff));
file_size_cmd[3] = (file_size >> 16 & (0xff));
file_size_cmd[4] = (file_size >> 8 & (0xff));
file_size_cmd[5] = (file_size & (0xff));
int crc = CRC16(file_size_cmd,len-2);
file_size_cmd[len-2] = crc & 0x00ff;
file_size_cmd[len-1] = ((crc >> 8) & 0x00ff);
i2c_write(fd,0x18,file_size_cmd,len);
return MI_TRUE;
}
static MI_BOOL send_file_every_package(int fd)
{
int len = sizeof(file_package);
FILE *fp;
size_t file_size;
int package_num;
MI_U8 package_buff[UPGRADE_DATA_PACKAGES_LENGHT] = {0};
fp = fopen(APPLICATION_PATH,"rb");
if (!fp)
{
perror("fopen error\n");
return MI_FALSE;
}
get_update_file_size(APPLICATION_PATH,&file_size);
if (file_size % UPGRADE_DATA_PACKAGES_LENGHT == 0 )
{
package_num = file_size / UPGRADE_DATA_PACKAGES_LENGHT;
}
else
{
package_num = (file_size / UPGRADE_DATA_PACKAGES_LENGHT) + 1;
}
printf("pageage_num == %d\n",package_num);
while (!feof(fp)/* condition */)
{
/* code */
int r_len = fread(package_buff,1,UPGRADE_DATA_PACKAGES_LENGHT,fp);
// 最后读出来不满128 ,用0xff补全。
if (r_len != UPGRADE_DATA_PACKAGES_LENGHT)
{
for (int i=r_len;i<UPGRADE_DATA_PACKAGES_LENGHT;i++)
{
package_buff[i] = 0xff;
}
}
memcpy(&file_package[2],package_buff,sizeof(package_buff));
int crc = CRC16(file_package,sizeof(file_package)-2);
file_package[sizeof(file_package)-2] = crc & 0x00ff;
file_package[sizeof(file_package)-1] = ((crc >> 8) & 0x00ff);
usleep(30 * 1000);
w_num++;
printf("send package process == [%03d]\n", ((w_num * 100)/package_num));
#if DEBUG
for(int i=0;i< len;i++)
{
printf("0x%02x ",file_package[i]);
if ((i+1) % 16 == 0)
printf("\n");
}
printf("\n");
#endif
memset(r_data,0,sizeof(r_data));
i2c_write(fd,0x18,file_package,len);
#if DEBUG
// for(int i=0;i< len;i++)
// {
// printf("0x%02x ",r_data[i]);
// if ((i+1) % 16 == 0)
// printf("\n");
// }
// printf("\n");
// int status = compare(r_data,file_package,20);
// if (status)
// {
// printf("send_file_every_package and receive cmd success!\n");
// }
// else
// {
// perror("send_file_every_package not equal receive cmd\n");
// }
//printf("read len == %d w_num == %d \n",len,w_num);
#endif
}
fclose(fp);
return MI_TRUE;
}
static MI_BOOL send_update_complete_cmd(int fd)
{
int len = sizeof(update_complete_cmd);
int crc = CRC16(update_complete_cmd,len-2);
update_complete_cmd[len-2] = crc & 0x00ff;
update_complete_cmd[len-1] = ((crc >> 8) & 0x00ff);
i2c_write(fd,0x18,update_complete_cmd,sizeof(update_complete_cmd));
return MI_TRUE;
}
static void print_register_value(unsigned char *p_buff,unsigned short len)
{
for(int i=0;i<len;i++)
{
printf("0x%02x " , p_buff[i]);
if ((i +1)% 16 == 0)
{
printf("\r\n");
}
}
printf("\r\n");
}
int open_i2c_dev(int i2cbus, char *filename, size_t size, int quiet)
{
int file, len;
len = snprintf(filename, size, "/dev/i2c/%d", i2cbus);
if (len >= (int)size) {
fprintf(stderr, "%s: path truncated\n", filename);
return -EOVERFLOW;
}
file = open(filename, O_RDWR);
if (file < 0 && (errno == ENOENT || errno == ENOTDIR)) {
len = snprintf(filename, size, "/dev/i2c-%d", i2cbus);
if (len >= (int)size) {
fprintf(stderr, "%s: path truncated\n", filename);
return -EOVERFLOW;
}
file = open(filename, O_RDWR);
}
if (file < 0 && !quiet) {
if (errno == ENOENT) {
fprintf(stderr, "Error: Could not open file "
"`/dev/i2c-%d' or `/dev/i2c/%d': %s\n",
i2cbus, i2cbus, strerror(ENOENT));
} else {
fprintf(stderr, "Error: Could not open file "
"`%s': %s\n", filename, strerror(errno));
if (errno == EACCES)
fprintf(stderr, "Run as root?\n");
}
}
return file;
}
static int check_funcs(int file)
{
unsigned long funcs;
/* check adapter functionality */
if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
fprintf(stderr, "Error: Could not get the adapter "
"functionality matrix: %s\n", strerror(errno));
return -1;
}
if (!(funcs & I2C_FUNC_I2C)) {
fprintf(stderr, MISSING_FUNC_FMT, "I2C transfers");
return -1;
}
return 0;
}
static int i2c_write(int fd,int slave_addr,unsigned char *p_data,unsigned short len)
{
struct i2c_rdwr_ioctl_data rdwr;
int ret = 0;
rdwr.nmsgs = 1;
rdwr.msgs = (struct i2c_msg *)malloc(rdwr.nmsgs * sizeof(struct i2c_msg));
if(!rdwr.msgs)
{
printf("msgs memery alloc error\n");
close(fd);
return -1;
}
if ((rdwr.msgs[0].buf = (unsigned char *)malloc(len * sizeof(unsigned char))) == NULL)
{
printf("buf memery alloc error...\n");
close(fd);
return -1;
}
(rdwr.msgs[0]).len = len;
(rdwr.msgs[0]).flags = !I2C_M_RD;
(rdwr.msgs[0]).addr = slave_addr;
memcpy((rdwr.msgs[0]).buf,p_data,len);
rdwr.nmsgs = 1;
ret = ioctl(fd, I2C_RDWR, (unsigned long) &rdwr);
if(ret < 0)
{
printf("Error during I2C_RDWR ioctl with error code: %d\n", ret);
return -1;
}
free(rdwr.msgs[0].buf);
free(rdwr.msgs);
return 0;
}
static int i2c_read(int fd,int slave_addr,unsigned char *w_data,
unsigned short w_len,unsigned char *p_data,unsigned short len)
{
struct i2c_rdwr_ioctl_data rdwr;
unsigned char val;
int ret;
rdwr.nmsgs = 2;
rdwr.msgs = (struct i2c_msg *)malloc(rdwr.nmsgs *sizeof(struct i2c_msg));
if(!rdwr.msgs)
{
printf("Memery alloc error\n");
close(fd);
return -1;
}
if ((rdwr.msgs[0].buf = (unsigned char *)malloc(w_len * sizeof(unsigned char))) == NULL)
{
printf("buf memery alloc error...\n");
close(fd);
return -1;
}
(rdwr.msgs[0]).len = w_len;
(rdwr.msgs[0]).flags = 0;
(rdwr.msgs[0]).addr = slave_addr;
memcpy((rdwr.msgs[0]).buf,w_data,w_len);
if ((rdwr.msgs[1].buf = (unsigned char *)malloc(len * sizeof(unsigned char))) == NULL)
{
printf("buf memery alloc error...\n");
close(fd);
return -1;
}
(rdwr.msgs[1]).len = len;
(rdwr.msgs[1]).flags = 1;
(rdwr.msgs[1]).addr = slave_addr;
ret = ioctl(fd, I2C_RDWR, (unsigned long) &rdwr);
if(ret < 0)
{
printf("Error during I2C_RDWR ioctl with error code: %d\n", ret);
return -1;
}
memcpy(p_data,(rdwr.msgs[1]).buf,len);
free(rdwr.msgs[0].buf);
free(rdwr.msgs[1].buf);
free(rdwr.msgs);
}
int main(int argc,char *argv[])
{
int fd;
char filename[20];
size_t update_file_size;
fd = open_i2c_dev(1, filename, sizeof(filename), 0);
if (fd < 0 || check_funcs(fd))
exit(1);
memset(r_data,0,sizeof(r_data));
send_get_version_cmd(fd,r_data,20);
printf("get version == %s\n",r_data);
usleep(30 * 1000);
send_enter_update_cmd(fd);
usleep(30 * 1000);
get_update_file_size(APPLICATION_PATH,&update_file_size);
printf("get update file size == %ld\n",update_file_size);
send_update_file_size_cmd(fd);
usleep(30 * 1000);
send_file_every_package(fd);
usleep(30 * 1000);
memset(r_data,0,sizeof(r_data));
send_update_complete_cmd(fd);
close(fd);
return 0;
}