I literally feel like I'm going crazy! I'm trying to write an exceptionally simple program that can request a list of local WiFi networks using an ESP8266 and the AT+CWLAP command. The issue doesn't lie in the UART or ESP8266 side however.
I've written a function that can send a string through UART to the ESP8266. If however I try and call this function and pass a literal string, for example: U_TxStr("Hello"), it causes the entire microcontroller to hang in the "CopyDataInit" startup ASM code section. I've tried adding a hard fault handler that I found online but this hasn't helped at all as the program doesn't even manage to get here!
If instead, I initialize a character array with a string, e.g: char str[16] = "Hello", and pass str as a pointer to the U_TxStr function, the program works fine and there are no issues. What could the issue be here? It feels like the microcontroller is failing to copy the string out of flash and into RAM (onto the stack?) causing it to just hang at initialization, does this sound right and how can I fix it?
I'm using CooCox and an STM32F0 Discovery board
Full code listing:
#include <stm32f0xx_gpio.h>
#include <stm32f0xx_rcc.h>
#include <stm32f0xx_usart.h>
#include <stm32f0xx_misc.h>
#include <string.h>
#define U_TX GPIO_Pin_2
#define U_RX GPIO_Pin_3
#define U_TXPS GPIO_PinSource2
#define U_RXPS GPIO_PinSource3
#define U_AF GPIO_AF_1
#define U_GPIO GPIOA
#define U_CHAN0 GPIO_Pin_0
#define U_CHAN1 GPIO_Pin_1
#define U_UIRQ USART2_IRQn
#define U_USART USART2
#define U_UBUFSIZ 512
char ubuf[U_UBUFSIZ] = {0};
volatile uint8_t devchan = 0;
volatile uint16_t dcnt = 0;
volatile uint32_t msec = 0, tlast = 0;
GPIO_InitTypeDef G;
USART_InitTypeDef U;
NVIC_InitTypeDef N;
void SysTick_Handler(void){
msec++;
}
volatile uint32_t f = 0;
static void hard_fault_handler_c(unsigned int * hardfault_args)
{
unsigned int stacked_r0;
unsigned int stacked_r1;
unsigned int stacked_r2;
unsigned int stacked_r3;
unsigned int stacked_r12;
unsigned int stacked_lr;
unsigned int stacked_pc;
unsigned int stacked_psr;
stacked_r0 = ((unsigned long) hardfault_args[0]);
stacked_r1 = ((unsigned long) hardfault_args[1]);
stacked_r2 = ((unsigned long) hardfault_args[2]);
stacked_r3 = ((unsigned long) hardfault_args[3]);
stacked_r12 = ((unsigned long) hardfault_args[4]);
stacked_lr = ((unsigned long) hardfault_args[5]);
stacked_pc = ((unsigned long) hardfault_args[6]);
stacked_psr = ((unsigned long) hardfault_args[7]);
for(;;);
}
void HardFault_Handler(void)
{
asm volatile(
"movs r0, #4\t\n"
"mov r1, lr\t\n"
"tst r0, r1\t\n" /* Check EXC_RETURN[2] */
"beq 1f\t\n"
"mrs r0, psp\t\n"
"ldr r1,=hard_fault_handler_c\t\n"
"bx r1\t\n"
"1:mrs r0,msp\t\n"
"ldr r1,=hard_fault_handler_c\t\n"
: /* no output */
: /* no input */
: "r0" /* clobber */
);
}
void USART2_IRQHandler(void){
uint8_t data;
if(USART_GetITStatus(U_USART, USART_IT_RXNE) != RESET){
USART_ClearITPendingBit(U_USART, USART_IT_RXNE);
data = USART_ReceiveData(U_USART);
if(dcnt<U_UBUFSIZ) ubuf[dcnt++] = data;
tlast = msec;
}
}
void U_TxByte(const char d){
USART_SendData(U_USART, d);
while(USART_GetFlagStatus(U_USART, USART_FLAG_TXE) == RESET);
}
void U_TxStr(const char *s){
while(*s){
U_TxByte(*s);
s++;
}
}
void U_WaitStr(uint32_t t){
while((msec-tlast)<t);
}
void U_ClrBuf(void){
memset(ubuf, 0, U_UBUFSIZ*sizeof(char));
dcnt = 0;
}
int main(void)
{
RCC_DeInit();
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
G.GPIO_Pin = U_TX | U_RX;
G.GPIO_Mode = GPIO_Mode_AF;
G.GPIO_OType = GPIO_OType_PP;
G.GPIO_PuPd = GPIO_PuPd_UP;
G.GPIO_Speed = GPIO_Speed_Level_1;
GPIO_Init(U_GPIO, &G);
GPIO_PinAFConfig(U_GPIO, U_TXPS, U_AF);
GPIO_PinAFConfig(U_GPIO, U_RXPS, U_AF);
G.GPIO_Pin = U_CHAN0 | U_CHAN1;
G.GPIO_Mode = GPIO_Mode_IN;
G.GPIO_OType = GPIO_OType_PP;
G.GPIO_PuPd = GPIO_PuPd_UP;
G.GPIO_Speed = GPIO_Speed_Level_1;
GPIO_Init(U_GPIO, &G);
if(GPIO_ReadInputDataBit(U_GPIO, U_CHAN0)) devchan += 1;
if(GPIO_ReadInputDataBit(U_GPIO, U_CHAN1)) devchan += 2;
N.NVIC_IRQChannel = U_UIRQ;
N.NVIC_IRQChannelPriority = 1;
N.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&N);
USART_DeInit(U_USART);
U.USART_BaudRate = 115200;
U.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
U.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
U.USART_Parity = USART_Parity_No;
U.USART_StopBits = USART_StopBits_1;
U.USART_WordLength = USART_WordLength_8b;
USART_Init(U_USART, &U);
USART_ClearITPendingBit(U_USART, USART_IT_RXNE);
USART_ITConfig(U_USART, USART_IT_RXNE, ENABLE);
USART_Cmd(U_USART, ENABLE);
SysTick_Config(SystemCoreClock/1000);
//Works
/*char str[12] = "AT+CWLAP\r\n";
U_ClrBuf();
U_TxStr(str);
U_WaitStr(500);*/
//Breaks
/*U_ClrBuf();
U_TxStr("AT+CWLAP\r\n");
U_WaitStr(500);*/
while(1)
{
}
}
Edit: For reference, I've tried a different board and get the same issue. Globally declaring the char arrays makes no difference either :(
Update: So I decided to give all of the available toolchains a go (just in case) - GCC Arm 4.8 to 5 and strangly, compiling with 4.8 does not give this issue! I'm yet to compare produced assemblies but it's strange that the issue seems to come with later GCC revisions.
1 Answer 1
STM32F0
Which has a Cortex M0 core.
Cortex M0 is sensitive to mis-alignment. Your problem sounds a lot like there is just a missing alignment statement in the linker skript, causing one version of the program to fail while trying to copy the data segement from flash to RAM.
Both sides must be 4-byte aligned for the usual startup copy code to work.
Your working program is slightly different in code or data size, masking the problem.
Explore related questions
See similar questions with these tags.
ROM
keyword available to you? \$\endgroup\$