Notes on Using SystemWorkbench with STM32 BluePill

I finally succumb to IDE madness... for awhile.

Similar projects worth following
I realize that I'm part of the dying crowd that will only use emacs as an IDE. I decided to live with SystemWorkbench for awhile. Lots of things had to be taken care of and my notes might help you.

Based on comments on I decided to give SystemWorkbench a go.

  • Hints for using the CDC USB Serial

    Al Williams04/11/2017 at 03:05 3 comments

    When you add the USB CDC serial to your project, you don't get much help about what to do next. The CDC_Transmit_FS call is pretty obvious. Give it a message and a length and it sends it. Fair enough.

    Receive, though is via a callback named CDC_Receive_FS. You don't call this. The framework calls it for you.

    Here's my version:

    static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len)
      /* USER CODE BEGIN 6 */
    uint32_t len=*Len;
    if (hUsbDeviceFS.dev_state != USBD_STATE_CONFIGURED)
       return USBD_FAIL;
    if (((Buf == NULL) || (Len == NULL)) || (*Len <= 0))
       return USBD_FAIL;
    /* Get data */
    uint8_t result = USBD_OK;
            result = USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
        while(result != USBD_OK);
           result = USBD_CDC_ReceivePacket(&hUsbDeviceFS);
        while(result != USBD_OK);
    // add data to FIFO
        while (len--)
           if (FIFO_INCR(RX_FIFO.head)==RX_FIFO.tail)
                 return USBD_FAIL;  // overrun
       return (USBD_OK);
      /* USER CODE END 6 */ 

    This in in one of the headers:

    #define  FIFO_SIZE 32  // must be 2^N
    #define FIFO_INCR(x) (((x)+1)&((FIFO_SIZE)-1))
    /* Structure of FIFO*/
    typedef struct FIFO
    uint32_t head;
    uint32_t tail;
        uint8_t data[FIFO_SIZE];
    } FIFO;
    extern FIFO RX_FIFO;

    Then you need a way to read it out, too

    /* Create FIFO*/
    FIFO RX_FIFO = {.head=0, .tail=0};
    // returns bytes read (could be zero)
    // would be easy to make it end early on a stop char (e.g., \r or \n)
    uint8_t VCP_read(uint8_t* Buf, uint32_t Len)
      uint32_t count=0;
    /* Check inputs */
      if ((Buf == NULL) || (Len == 0))
      return 0;
    while (Len--)
    if (RX_FIFO.head==RX_FIFO.tail) return count;
    return count;

  • Enabling Semihosted Printf

    Al Williams04/03/2017 at 23:48 5 comments

    If you don't want printf to go to a serial port, perhaps you'd like to have it redirect to the gdb console (inside Eclipse).

    1. Add to your linker options:

    -specs=rdimon.specs -lrdimon

    2. In your debug configuration, find Run Commands and add:

    monitor arm semihosting enable

    3. In your main() make this call early (before calling printf):


    That's it. Now printf will go to your console.

  • Retarget Printf and Friends to UART

    Al Williams04/03/2017 at 12:35 2 comments

    1. Make sure you have enough stack! If you didn't set it at project generation time, fix it in your .ld file (and be sure to fix it in the CubeMX project too in case you regenerate.
    2. Also, create a dummy project with the IDE and NOT CubeMX. Steal the syscalls.c file from that project and put it in your project.
    3. Obviously, you need to set up the UART in CubeMX.
    4. Add this:
    int __io_putchar(int ch)
    uint8_t ch8=ch;
    HAL_UART_Transmit(&huart1,(uint8_t *)&ch8,1,HAL_MAX_DELAY);
    return ch;
    int __io_getchar()
    uint8_t ch8;
    return 0;

    Done! Mysterious crashes means your stack is too small or you have left the boot jumpers set funny and SP isn't set to what you think it is.

  • Notes

    Al Williams04/03/2017 at 12:30 0 comments


    2. Install CubeMX from the ST web site into Eclipse.

    3. You must have ST-Link 2 or 2-1 for this board. Appears to not work with ST-Link 1 even though other tools can handle that.

    4. CubeMX has a bug if you use PLL clock. In SystemClock_Config the line should look like this: RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;

    5. The settings for OpenOCD are hardwired into .custom.cfg in your project directory when you create the configuration. So if you ever change anything, it looks like you have to nuke or edit that file.

    6. IMPORTANT: the debugger won't work until you change the openOCD config to use: reset_config trst_only. The defaults will NOT work.

    7. If you have the BOOT jumpers set for boot load, debugging will appear to work. However, you will get the bootloader stackpointer which is is a very small stack and may overlay your C library data. This will lead to strange and unpredictable behavior.

    8. If you install eGit, you get Git integration.

    9. If you install the TM Terminal, you can have a terminal inside the IDE. It supposedly supports serial, but on Ubuntu, the RXTX configuration is hosed. Instead of fixing it, I run a shell terminal and run picocom inside of it. Works fine.

View all 4 project logs

Enjoy this project?



Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates