0
\$\begingroup\$

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.

\$\endgroup\$
6
  • \$\begingroup\$ I'm not familiar with the STM32, but do you have the ROM keyword available to you? \$\endgroup\$ Oct 5, 2016 at 19:31
  • \$\begingroup\$ What exactly do you mean by hang? If there would be an error in accessing either RAM or flash you'd end up with a bus error or something similar and probably enter the hard fault manager. If that doesn't happen, how do you define it "hanging"? Is it executing an endless loop or does it execute nothing? Maybe the initialization assembly is buggy. \$\endgroup\$
    – Arsenal
    Oct 5, 2016 at 19:40
  • \$\begingroup\$ So when I start the program, a working program will automatically jump to the start of main. After starting the debugger however, this program does literally nothing. If I pause the debugger, it stops on the same line of the initialisation code every time, if I try and step into, over or out of the code, it returns to the same state as before I pressed pause. If I then pause again, it is still stuck at this line. I'm not too sure if the initialisation code is dodgy as its worked fine previously! \$\endgroup\$
    – Pyrohaz
    Oct 5, 2016 at 19:43
  • 1
    \$\begingroup\$ It could be the linker. I'd check the memory and see if you can find the literal string in there. \$\endgroup\$ Oct 5, 2016 at 20:02
  • \$\begingroup\$ Looks like a mismatch between startup code and linker script. \$\endgroup\$ Oct 6, 2016 at 8:20

1 Answer 1

1
\$\begingroup\$

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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.