Search code examples
windowsusbprintfkeil

how to redirect Keil printf out through STM32F4xx USB to connected Windows computer


How can I configure Keil uVision5 to redirect printf output from STM32F4xx out through MCU's USB interface? Then, USB will connect to a Windows computer, virtual port driver, and a terminal program.

I cannot find an example uVision5 project that configures printf to output through the STM32F4xx MCU's USB interface.


Solution

  • The USB of the STM32F4xx MCU has to implement the USB CDC as device class or interface class (https://en.wikipedia.org/wiki/USB_communications_device_class) and in host mode (USB OTG) in its firmware. On the PC's USB has to be created a virtual COM port (driver) to process the RS232 protocol that the STM32F4 sends over the USB CDC (in host mode). When the CDC firmware on the STM32F4 is working correctly, on linux the STM32F4 appears i.e. as /dev/ttyACM0 and this can be accessed with standard RS232 terminal programs.

    basics -> http://www.keil.com/support/man/docs/rlarm/rlarm_usb_create_cdc_acm.htm

    Here is a basic example how to send serial data over USB CDC (that on pc's USB appears as a Virtual COM port i.e. /dev/ttyACM0): http://visualgdb.com/tutorials/arm/stm32/usb/

    See also this http://stm32f4-discovery.net/2014/08/library-24-virtual-com-port-vcp-stm32f4xx/

    Follow or adapt the tutorial above to linux (http://visualgdb.com/tutorials/arm/stm32/usb/).

    To redirect printf() to USB CDC override the standard I/O routines like in the following. The ARM version of printf() invokes these routines then, see this https://mcuoneclipse.com/2014/07/11/printf-and-scanf-with-gnu-arm-libraries/ (the ARM version of printf() is very different from the x86/x64 version of printf()):

    #include<sys/stat.h>
    
    extern"C"
    {
       int _fstat (int fd, struct stat *pStat)
        {
            pStat->st_mode = S_IFCHR;
           return 0;
        }
    
       int _close(int)
        {
           return -1;
        }
    
       int _write (int fd, char *pBuffer, int size)
        {
           return VCP_write(pBuffer, size);
        }
    
       int _isatty (int fd)
        {
           return 1;
        }
    
       int _lseek(int, int, int)
        {
           return -1;
        }
    
       int _read (int fd, char *pBuffer, int size)
        {
           for (;;)
            {
               int done = VCP_read(pBuffer, size);
               if (done)
                   return done;
            }
        }
    }
    

    Or use the ARM semihosting interface (http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0471c/Bgbjhiea.html). It will provide the functionality automatically to redirect printf() to USB CDC

    More information:

    This is an example how to implement a USB-RS232 adapter: http://www.wolinlabs.com/blog/stm32f4.virtual.com.port.html

    The git also contains many interesting files git clone https://github.com/rowol/stm32_discovery_arm_gcc