N32替换STM32记录
前言
目前大形势影响,芯片价格日益上涨,采购周期变长,导致国产芯片替代进口芯片成为大趋势,该文章记录了使用国民技术的N32替换STM32的操作流程。
话不多说,上步骤。
一、工程配置
1.安装硬件库
硬件库为厂家提供的资料,如下图所示,双击安装,使得keil能够找到该芯片。
2.更改J-Flash配置
由于Keil官方没有对该芯片的支持,所以J-Link下载时也无法找到该芯片,所以需要手动添加芯片。更改步骤官方提供有说明文档。
主要步骤是:
- 修改JLinkDevices 配置文档
- 添加Nationstech 的下载算法文件
- 添加Nationstech 的JFlash 工程文件
- 添加解锁Nationstech 芯片读保护L1 等级的应用程序
进行如上步骤后,启动J-Flash就能够扫描并连接到芯片,但是有可能keil链接的J-Flash和安装的J-Flash不是一个路径,所以将配置好的J-Flash文件替换keil下Keil5\ARM\Segger目录文件,就能够正常下载调试。
3.更改芯片
4.添加驱动文件
将N32的底层驱动库拷贝到工程目录下,并将include路径添加进去。
5.更改全局变量
6.将启动文件和驱动文件替换为N32库文件
7.将所有的stm32l1xx替换为n32g45x
二、底层驱动函数接口对照表
更改代码,将STM32的驱动函数替换为N32的驱动函数,这部分比较繁琐,需要慢慢替换,下面是我整理的替换对照表。
STM32名称 | N32名称 |
|
USART_TypeDef |
|
|
RCC_AHBPeriphClockCmd | RCC_EnableAHBPeriphClk |
|
RCC_APB1PeriphClockCmd | RCC_EnableAPB1PeriphClk |
|
RCC_APB2PeriphClockCmd | RCC_EnableAPB2PeriphClk |
|
RCC_APB1Periph_UART5 | RCC_APB1_PERIPH_UART5 |
|
RCC_AHBPeriph_GPIOB | RCC_AHB_PERIPH_GPIOB |
|
|
|
|
GPIO_InitTypeDef | GPIO_InitType |
|
GPIO_Pin | Pin |
|
GPIO_Mode_AF | GPIO_Mode_AF_PP |
|
GPIO_Mode_OUT | GPIO_Mode_Out_PP |
|
GPIO_Speed_40MHz | GPIO_Speed_50MHz |
|
GPIO_Init | GPIO_InitPeripheral |
|
GPIO_PinSource0 | GPIO_PIN_SOURCE0 |
|
GPIO_PinAFConfig | 无需配置该位 |
|
GPIO_AF_SPI1 |
|
|
|
|
|
USART_InitTypeDef | USART_InitType |
|
USART_TypeDef | USART_Module |
|
USART_BaudRate | BaudRate |
|
USART_WordLength | WordLength |
|
USART_Parity | Parity |
|
USART_StopBits | StopBits |
|
USART_HardwareFlowControl | HardwareFlowControl |
|
USART_Mode | Mode |
|
USART_WordLength_8b | USART_WL_8B |
|
USART_Parity_No | USART_PE_NO |
|
USART_StopBits_1 | USART_STPB_1 |
|
USART_HardwareFlowControl_None | USART_HFCTRL_NONE |
|
USART_Mode_Rx | USART_MODE_RX |
|
USART_Mode_Tx | USART_MODE_TX |
|
USART_IT_RXNE | USART_INT_RXDNE |
|
USART_IT_IDLE | USART_INT_IDLEF |
|
USART_FLAG_TC | USART_FLAG_TXC |
|
USART_FLAG_RXNE | USART_FLAG_RXDNE |
|
|
|
|
USART_ITConfig | USART_ConfigInt |
|
USART_Cmd | USART_Enable |
|
USART_GetITStatus | USART_GetIntStatus |
|
|
|
|
SPI_InitTypeDef | SPI_InitType |
|
SPI_Direction | DataDirection |
|
SPI_Mode | SpiMode |
|
SPI_DataSize | DataLen |
|
SPI_CPOL | CLKPOL |
|
SPI_CPHA | CLKPHA |
|
SPI_NSS | NSS |
|
SPI_BaudRatePrescaler | BaudRatePres |
|
SPI_FirstBit | FirstBit |
|
SPI_CRCPolynomial | CRCPoly |
|
SPI_Direction_2Lines_FullDuplex | SPI_DIR_DOUBLELINE_FULLDUPLEX |
|
SPI_Mode_Master | SPI_MODE_MASTER |
|
SPI_DataSize_8b | SPI_DATA_SIZE_8BITS |
|
SPI_CPOL_Low | SPI_CLKPOL_LOW |
|
SPI_CPHA_1Edge | SPI_CLKPHA_FIRST_EDGE |
|
SPI_NSS_Soft | SPI_NSS_SOFT |
|
SPI_BaudRatePrescaler_2 | SPI_BR_PRESCALER_2 |
|
SPI_FirstBit_MSB | SPI_FB_MSB |
|
SPI_I2S_FLAG_RXNE | SPI_I2S_RNE_FLAG |
|
SPI_I2S_FLAG_TXE | SPI_I2S_TE_FLAG |
|
SPI_I2S_GetFlagStatus | SPI_I2S_GetStatus |
|
SPI_SendData | SPI_I2S_TransmitData |
|
SPI_ReceiveData | SPI_I2S_ReceiveData |
|
SPI_Cmd | SPI_Enable |
|
|
|
|
FLASH_FLAG_PGAERR | FLASH_FLAG_PGERR |
|
FLASH_FLAG_SIZERR |
|
|
FLASH_FLAG_OPTVERR | FLASH_FLAG_OPTERR |
|
FLASH_FLAG_OPTVERRUSR |
|
|
FLASH_COMPLETE | FLASH_COMPL |
|
FLASH_ErasePage | FLASH_EraseOnePage |
|
FLASH_FastProgramWord | FLASH_ProgramWord |
|
FLASH_Status | FLASH_STS |
|
DATA_EEPROM_ProgramWord | FLASH_ProgramWord |
|
DATA_EEPROM_Unlock | FLASH_Unlock |
|
|
|
|
IWDG_WriteAccessCmd | IWDG_WriteConfig |
|
IWDG_SetPrescaler | IWDG_SetPrescalerDiv |
|
IWDG_SetReload | IWDG_CntReload |
|
IWDG_WriteAccess_Enable | IWDG_WRITE_ENABLE |
|
IWDG_Prescaler_64 | IWDG_PRESCALER_DIV64 |
|
IWDG_ReloadCounter | IWDG_ReloadKey |
|
|
|
|
TIM_TimeBaseInitTypeDef | TIM_TimeBaseInitType |
|
TIM_CounterMode | CntMode |
|
TIM_ClockDivision | ClkDiv |
|
TIM_Period | Period |
|
TIM_Prescaler | Prescaler |
|
TIM_CKD_DIV1 | TIM_CLK_DIV1 |
|
TIM_CounterMode_Up | TIM_CNT_MODE_UP |
|
|
|
|
TIM_TimeBaseInit | TIM_InitTimeBase |
|
TIM_GetITStatus | TIM_GetIntStatus |
|
TIM_PSCReloadMode_Immediate | TIM_PSC_RELOAD_MODE_IMMEDIATE |
|
TIM6->CR1 | TIM6->CTRL1 |
|
TIM6->SR | TIM6->STS |
|
TIM6->EGR | TIM6->EVTGEN |
|
TIM6->ARR | TIM6->AR |
|
三、踩坑记录
经过上面的替换,应该可以编译过去了,但是这指示开始,后面悲剧的踩坑大战才刚刚开始。
1.仿真卡死
程序仿真卡死,单步调试发现卡死在OSInit()函数里面,这个函数是OS的初始化函数,所以应该是OS配置的问题,排查下来发现是启动文件里面的OS启动项没有更改,更改如下:
2.DMA配置出错
程序能够进入到任务中后,调试发现无法进入到串口接收中断,但是示波器中有数据,而且中断都没有进入,应该是卡死在优先级高的中断中,排查发现,是DMA发送中断的配置有问题,导致一直卡死在DMA中断中。下面是DMA部分的配置。
3.Flash配置
由于国民芯片和STM32芯片的FLASH划分有区别,所以FLASH的替换是比较费事的部分,先对比一下两个片子的区别:
STM32L151的flash部分:
N32G455芯片的flash部分:
可以看出STM32单独有EEPROM的划分,而N32是没有的,只有flash部分。所以要注意两点:
- Flash空间的问题,STM32可用空间要比N32的空间大;
- 底层接口函数,STM32有操作EEPROM的函数,而N32没有,只能使用flash操作函数。
下面是flash部分的操作:
4.bootloader移植
由于本项目采用bootloader引导主程序的方式,因此要注意烧写空间的配置,配置点在下面位置:
当单独调试其中的程序时,烧写程序需要将整个flash擦除,要不运行不正常。
5.OS初始化卡死
又遇到程序卡死问题,这次是主程序,而且主程序起始地址为0x8000000时单独运行良好,但是改成0x8007000用bootloader跳转过去就卡死,也是卡死在OS的初始化中。因为单独运行良好,所以排查起来困难些。最终定位是堆栈和堆的空间设置太大了,设置小了后就可以运行。更改该空间的位置如下:
而且问题还不是堆栈的空间不够用,是空间设置太大了。有点无语。
6.程序跳转后运行不正常
这是最后的问题,程序能够从bootloader跳转,但是运行不正常,咨询了厂家技术人员,技术人员反馈可以采用分散加载的方式进行排查,也就是让芯片直接在主程序烧录的位置启动,分散加载的教程网上比较多,主要需要设置烧录域和启动域地址,还有VTOR寄存器,
配置如下所示:
需要编写*.ini文件更改VTOR,ini文件编写如下:
在keil中加载,使得软件启动后先配置单片机:
配置好后可以实现分散加载,能够是程序在烧录位置启动,发现程序分散加载可以运行正常,但是bootloader跳转不正常,因此需要排查跳转部分的问题。最终定位STM32在主程序启动时不会重启向量表,而N32会重启向量表,在主程序启动位置更改如下:
跳转部分代码如下: