1、基本问题
1.1、J-Link Failed to get CPU status after 4 retries Retry
1.2、CMU_ClockEnable(cmuClock_CORELE, true);
1.3、焊接了好几块板子,Jlink都连不上单片机,最后是把电源的旁路电容都加上才能连上。EFM32单片机对电源的要求较高,必须在芯片的电源上做好滤波和退耦,否则会影响j-link的连接和调试
1.4 EFM32 如果用LEUART,不要使用内部低频晶振做输入,偏频较大
1.5 void LEUART_Tx(LEUART_TypeDef *leuart, uint8_t data) 这个接口在多次发送会出现死循环的情况。所以还是换用
void LEUART_TxExt(LEUART_TypeDef *leuart, uint16_t data)
2、串口升级
2.1工具
Tera Term
J-FLASH
2.2 代码
/*********************************************
* @文件: main.c
* @作者: cjx
* @版本: v1.0.0
* @时间: 2018-06-22
* @电话: 18770053277
* @概要:
*********************************************/
#include "apll.h"
#include "ioctrl.h"
#include "xmodem.h"
#define UPDATE_COMMAND_WAIT_TIME 5000
#define UPDATE_WAIT_TIME 10000
int main(void)
{
T_U32 u32StartTime, u32StopTime;
S_FlashInfo stFlashInfo;
S_FlashRead stFlashRead;
S_FlashWrite stFlashWrite;
S_FlashErase stFlashErase;
DRIVER_SYS_Open();
DRIVER_FLASH_Open();
DRIVER_UART_Open();
stFlashRead.u32Addr = FLASH_INFO_ADDR;
stFlashRead.pu8Data = (T_U8 *)&stFlashInfo;
stFlashRead.u32Len = sizeof(stFlashInfo);
DRIVER_FLASH_Ioctl(E_FLASH_IOCTL_CMD_READ, &stFlashRead);
if(stFlashInfo.u32Ver > 0xff)
{
//stFlashInfo.u32Ver = 0;
stFlashInfo.u32AppAddr = FLASH_APP1_ADDR;
stFlashInfo.u32UpdateAddr = FLASH_APP1_ADDR;
}
DRIVER_UART_Write("Please Input Command!
", sizeof("Please Input Command!
")-1);
DRIVER_SYS_Ioctl(E_SYS_IOCTL_CMD_GET_TIME, &u32StartTime);
while(1)
{
unsigned char c = 0;
c = 0;
xgetc_nowait(&c);
switch(c)
{
case 'U': case 'u': // Upload.
{
stFlashErase.u32Addr = stFlashInfo.u32UpdateAddr;
stFlashErase.u32Pages = FLASH_APP_PAGES;
if(RET_FAILED==DRIVER_FLASH_Ioctl(E_FLASH_IOCTL_CMD_ERASE, &stFlashErase))
{
goto error;
}
DRIVER_UART_Write("Please Update!
", sizeof("Please Update!
")-1);
if(1 == xmodem(stFlashInfo.u32UpdateAddr, stFlashInfo.u32UpdateAddr+FLASH_APP_PAGES*FLASH_PAGE_SIZE))
{
stFlashInfo.u32Ver = (stFlashInfo.u32Ver+1)%256;
if(FLASH_APP1_ADDR == stFlashInfo.u32UpdateAddr)
{
stFlashInfo.u32AppAddr = FLASH_APP1_ADDR;
stFlashInfo.u32UpdateAddr = FLASH_APP2_ADDR;
}else
{
stFlashInfo.u32AppAddr = FLASH_APP2_ADDR;
stFlashInfo.u32UpdateAddr = FLASH_APP1_ADDR;
}
stFlashWrite.u32Addr = FLASH_INFO_ADDR;
stFlashWrite.pu8Data = (T_U8 *)&stFlashInfo;
stFlashWrite.u32Len = sizeof(stFlashInfo);
stFlashErase.u32Addr = FLASH_INFO_ADDR;
stFlashErase.u32Pages = FLASH_INFO_PAGES;
DRIVER_FLASH_Ioctl(E_FLASH_IOCTL_CMD_ERASE, &stFlashErase);
DRIVER_FLASH_Ioctl(E_FLASH_IOCTL_CMD_WRITE, &stFlashWrite);
DRIVER_UART_Write("Update Success!
", sizeof("Update Success!
")-1);
}else
{
goto error;
}
goto end;
#if 0
while(1)
{
if(xgetc(&c))
{
u32StartTime = u32StopTime;
}
DRIVER_SYS_Ioctl(E_SYS_IOCTL_CMD_GET_TIME, &u32StopTime);
if((u32StopTime-u32StartTime) > UPDATE_WAIT_TIME)
{
goto end;
}
}
#endif
}
break;
#if 0
case 'T': case 't': // Write to user page.
//xmodem(USER_PAGE_START_ADDR, USER_PAGE_END_ADDR);
break;
case 'P': case 'p': // Write to lock bits.
//xmodem(LOCK_PAGE_START_ADDR, LOCK_PAGE_END_ADDR);
break;
#endif
case 'B': case 'b': // Boot into new program.
goto end;
break;
default:
break;
}
DRIVER_SYS_Ioctl(E_SYS_IOCTL_CMD_GET_TIME, &u32StopTime);
if((u32StopTime-u32StartTime) > UPDATE_COMMAND_WAIT_TIME)
{
goto end;
}
}
end:
if(stFlashInfo.u32Ver > 0xff)
{
DRIVER_UART_Write("Don't Have App!
", sizeof("Don't Have App!
")-1);
DRIVER_SYS_Halt();
}else
{
DRIVER_UART_Write("Into App!
", sizeof("Into App!
")-1);
T_S8 s8StartAddr[] = "Start Addr = 0x00000000
";
T_U8 u8i=0,u8hex;
T_S8 s8Addr[4];
T_U32 u32Addr = stFlashInfo.u32AppAddr;
for(u8i=0; u8i<4; u8i++)
{
u8hex = u32Addr;
u8hex %= 16;
if(u8hex > 9)
{
s8Addr[u8i] = u8hex - 10+ 'a';
}else
{
s8Addr[u8i] = u8hex + '0';
}
u32Addr >>= 4;
}
s8StartAddr[19] = s8Addr[3];
s8StartAddr[20] = s8Addr[2];
s8StartAddr[21] = s8Addr[1];
s8StartAddr[22] = s8Addr[0];
DRIVER_UART_Write(s8StartAddr, 25);
typedef unsigned int (*ENTRY_FUNC_TYPE)(void);
ENTRY_FUNC_TYPE Goto;
Goto = (ENTRY_FUNC_TYPE)(*(unsigned int *)(stFlashInfo.u32AppAddr+4));
__set_MSP(*(unsigned int*)stFlashInfo.u32AppAddr);
Goto();
while(1);
}
error:
DRIVER_UART_Write("Update Fail!
", sizeof("Update Fail!
")-1);
SCB->AIRCR = 0x05FA0004;
while(1);
}
/*********************************************
* @文件: driverFlash.c
* @作者: cjx
* @版本: v1.0.1
* @时间: 2018-11-09
* @概要: Flash驱动
*********************************************/
#include "baseType.h"
#include "ioctrl.h"
/********************************************
*功能:打开函数
*输入:无
*输出:无
*条件:无
*返回:成功:RET_SUCCESS
失败:RET_FAILED
注意:
*********************************************/
T_S32 DRIVER_FLASH_Open(T_VOID)
{
MSC_Init();
#if 0
// Write MSC unlock code to enable interface.
MSC->LOCK = MSC_UNLOCK_CODE;
#if defined(EMU_CMD_EM01VSCALE2)
// Scale voltage up to allow FLASH programming
EMU->CMD = EMU_CMD_EM01VSCALE2;
while (EMU->STATUS & EMU_STATUS_VSCALEBUSY);
#endif
// Enable memory controller.
MSC->WRITECTRL |= MSC_WRITECTRL_WREN;
#endif
return RET_SUCCESS;
}
/********************************************
*功能:读取函数
*输入:输出数据 及 数据长度
*输出:无
*条件:无
*返回:成功:RET_SUCCESS
失败:RET_FAILED
或者长度
注意:
*********************************************/
T_S32 DRIVER_FLASH_Read(T_S8 *ps8DataBuf, T_S32 s32BufLen)
{
T_S32 s32DataLen = 0;
return s32DataLen;
}
/********************************************
*功能:事件标志
*输入:无
*输出:无
*条件:无
*返回:成功:RET_SUCCESS
失败:RET_FAILED
注意:
*********************************************/
T_S32 DRIVER_FLASH_Pop(T_VOID)
{
return RET_SUCCESS;
}
/********************************************
*功能:控制接口
*输入:s32Cmd :命令类型
pvData:控制数据或者返回
数据
*条件:无
*返回:成功:RET_SUCCESS
失败:RET_FAILED
*********************************************/
T_S32 DRIVER_FLASH_Ioctl(T_S32 s32Cmd, T_VOID *pvData)
{
T_S32 s32Ret = RET_SUCCESS;
switch(s32Cmd)
{
case E_FLASH_IOCTL_CMD_ERASE:
{
T_U32 u32i = 0;
S_FlashErase *pst = (S_FlashErase *)pvData;
__disable_irq();
for(u32i = 0; u32i < pst->u32Pages; u32i++)
{
//DRIVER_FLASH_Open();
if(mscReturnOk != MSC_ErasePage((uint32_t *)(pst->u32Addr + u32i*FLASH_PAGE_SIZE)))
{
s32Ret = RET_FAILED;
}
#if 0
MSC->LOCK = MSC_UNLOCK_CODE;
MSC->ADDRB = pst->u32Addr + u32i*FLASH_PAGE_SIZE;// Load address.
MSC->LOCK = MSC_UNLOCK_CODE;
MSC->WRITECMD = MSC_WRITECMD_LADDRIM;
MSC->LOCK = MSC_UNLOCK_CODE;
MSC->WRITECMD = MSC_WRITECMD_ERASEPAGE; // Send Erase Page command.
while (MSC->STATUS & MSC_STATUS_BUSY); // Waiting for erase to complete.
#endif
}
__enable_irq();
}
break;
case E_FLASH_IOCTL_CMD_WRITE:
{
S_FlashWrite *pst = (S_FlashWrite *)pvData;
T_U32 u32WLen = pst->u32Len;
if(u32WLen%4 != 0)
{
u32WLen = u32WLen + (4 - u32WLen%4);
}
//DRIVER_FLASH_Open();
__disable_irq();
if(MSC_WriteWord((uint32_t *)pst->u32Addr, pst->pu8Data, u32WLen))
{
s32Ret = RET_FAILED;
}
__enable_irq();
#if 0
T_U32 u32i = 0;
for(u32i = 0; u32i < pst->u32Len; u32i++)
{
MSC->LOCK = MSC_UNLOCK_CODE;
MSC->WRITECTRL |= MSC_WRITECTRL_WREN;
MSC->LOCK = MSC_UNLOCK_CODE;
MSC->ADDRB = pst->u32Addr + 4*u32i; // Load address.
MSC->WRITECMD = MSC_WRITECMD_LADDRIM;
MSC->LOCK = MSC_UNLOCK_CODE;
MSC->WDATA = 0x11111111;//pst->pu8Data[u32i]; // Load data.
MSC->WRITECMD = MSC_WRITECMD_WRITEONCE; // Trigger write once.
while (MSC->STATUS & MSC_STATUS_BUSY); // Waiting for the write to complete.
}
#endif
}
break;
case E_FLASH_IOCTL_CMD_READ:
{
T_U32 u32i = 0;
S_FlashRead *pst = (S_FlashRead *)pvData;
for(u32i = 0; u32i < pst->u32Len; u32i++)
{
pst->pu8Data[u32i] = *(T_U8 *)(pst->u32Addr + u32i);
}
}
break;
}
return s32Ret;
}
/********************************************
*功能:写入函数
*输入:无
*输出:无
*条件:无
*返回:成功:RET_SUCCESS
失败:RET_FAILED
或者长度
注意:
*********************************************/
T_S32 DRIVER_FLASH_Write(T_S8 *ps8DataBuf, T_S32 s32BufLen)
{
return s32BufLen;
}
static unsigned int gRamBuf[256];
void BSP_FlashWrite(unsigned int Addr, unsigned char *lpBuf, unsigned short n)
{
unsigned char *lpOBJ = (unsigned char *)gRamBuf;
unsigned int *lpAddr = gRamBuf;
unsigned short i;
for(i = 0; i < n; i++)
{
lpOBJ[i] = lpBuf[i];
}
for(i = 0; i < n; i += 4)
{
MSC->ADDRB = Addr+i; // Load address.
MSC->WRITECMD = MSC_WRITECMD_LADDRIM;
MSC->WDATA = *lpAddr++; // Load data.
MSC->WRITECMD = MSC_WRITECMD_WRITEONCE; // Trigger write once.
while (MSC->STATUS & MSC_STATUS_BUSY); // Waiting for the write to complete.
}
}
#include
#include "em_device.h"
#include "ioctrl.h"
#include "xmodem.h"
static unsigned int gRawBuf[2][sizeof(XMODEM_PACKET_TYPE)>>2];
static unsigned short CRC16E(unsigned char *lpBuf, unsigned short n)
{
unsigned short crc = 0x0;
unsigned short i;
for (i = 0; i < n; i++)
{
crc = (crc >> 8) | (crc << 8);
crc ^= lpBuf[i];
crc ^= (crc & 0xff) >> 4;
crc ^= crc << 12;
crc ^= (crc & 0xff) << 5;
}
return crc;
}
static unsigned short XMODEM_Verify(XMODEM_PACKET_TYPE *Struct, unsigned char Reference)
{
if (Struct->Number == Reference)
{
unsigned short crc = (Struct->CRCH<<8)|Struct->CRCL;
if(crc == CRC16E(Struct->Data, XMODEM_DATA_SIZE))
{
return 0;
}
}
return -1;
}
static void XMODEM_Wait(void)
{
unsigned int i;
while (1)
{
xputc(XMODEM_NCG);
for (i = 0; i < 2000000; i++)
{
if(xkbhit())
{
return;
}
}
}
}
int xmodem(unsigned int Base, unsigned int End)
{
XMODEM_PACKET_TYPE *Struct;
unsigned int Addr, i;
unsigned char Sequence = 1;
#if 0
for (Addr = Base; Addr < End; Addr += FLASH_PAGE_SIZE)
{
BSP_FlashErase(Addr);
}
#endif
XMODEM_Wait();
Addr = Base;
while (1)
{
// Swap buffer for packet buffer.
Struct = (XMODEM_PACKET_TYPE *)gRawBuf[Sequence & 1];
// Fetch the first byte of the packet explicitly, as it defines the
// rest of the packet.
Struct->Header = xgetc();
// Check for end of transfer.
if (Struct->Header == XMODEM_EOT)
{
// Acknowledget End of transfer.
xputc(XMODEM_ACK);
return 1;
}
// If the header is not a start of header (SOH), then cancel
// the transfer.
if (Struct->Header != XMODEM_SOH)
{
return -1;
}
// Fill the remaining bytes packet.
// Byte 0 is padding, byte 1 is header.
for (i = 2; i < sizeof(XMODEM_PACKET_TYPE); i++)
{
((unsigned char *)Struct)[i] = xgetc();
}
/* Packet Verify */
if(0 != XMODEM_Verify(Struct, Sequence))
{
// On a malformed packet, we send a NAK, and start over.
xputc(XMODEM_NAK);
return -1;
}
Sequence++;
// Write data to flash.
if(Addr < End)
{
//BSP_FlashWrite(Addr, Struct->Data, XMODEM_DATA_SIZE);
//memset(Struct->Data, 0x11, XMODEM_DATA_SIZE);
S_FlashWrite stFlashWrite;
stFlashWrite.u32Addr = Addr;
stFlashWrite.pu8Data = Struct->Data;
stFlashWrite.u32Len = XMODEM_DATA_SIZE;
if(RET_FAILED==DRIVER_FLASH_Ioctl(E_FLASH_IOCTL_CMD_WRITE, &stFlashWrite))
{
return -1;
}
Addr += XMODEM_DATA_SIZE;
}
// Send ACK.
xputc(XMODEM_ACK);
}
}
2.3 编写软件注意事项
1)操作flash要关闭中断
2)flash写接口要是4的倍数
3)应用程序编译时需要修改起始地址
iar的话需要在 iar的安装路径下找到 Option->Linker->Config里面的 .icf文件
2.4升级步骤
1)打开Tera Term,设置好 串口及 波特率,复位单片机出现下面的信息,按u进入升级
选择 File->Transfer->XMODEM->send 找到发送文件即可