1 Section: Understanding shared peripherals (pg 290)
2 Section: Introducing the STM USB driver stack (pg 292)
3 Section: Developing a StreamBuffer USB virtual COM port (pg 300)
Chapter 11: bugs and clarifications
12/4/2021
Chapter 11: Sharing Hardware Peripherals across Tasks (pg 289)
● Bug in the book, page 290
o The "STM USB virtual COM port drivers" do not need to be installed on Windows 10.
o Also, when I tried to install them on Windows 10, I got this error:
o The STM documentation states, "Starting from Windows 10, the STSW-STM32102 driver is no more adequate and the usage of the native inbox driver is recommended." Apparently, this means that the driver isn't needed, and the COM port will work without the STM driver.
o Additional info:
● Tip, page 290,
o When I clicked on the Tera Term installer, it took quite a while before getting the first installation GUI. Initially, I mistakenly thought the installer didn't run when I clicked on it.
● Additional info, page 291
o USB CDC is the USB communications device class.
o https://en.wikipedia.org/wiki/USB_communications_device_class
■ "The device attaches to an RS-232 communications line and the operating system on the USB side makes the USB device appear as a traditional RS-232 port."
● Additional info, page 292
o Info about STM32CubeMX:
■ https://www.freertos.org/FreeRTOS-Plus/BSP_Solutions/ST/STM32CubeMX.html
● Additional info, pages 294f
o Programs for Chapter 11
■ mainRawCDC.c
Chapter_11\Src\mainRawCDC.c
■ mainUsbStreamBuffer.c
Chapter_11\Src\mainUsbStreamBuffer.c
Drivers\HandsOnRTOS\VirtualCommDriver.c
Drivers\HandsOnRTOS\VirtualCommDriver.h
Middleware\ST\STM32_USB_Device_Library\Class\CDC\Src\usbd_cdc.c
■ mainUsbStreamBufferMultiTask.c
Chapter_11\Src\mainUsbStreamBufferMultiTask.c
Drivers\HandsOnRTOS\VirtualCommDriverMultiTask.c
Drivers\HandsOnRTOS\VirtualCommDriverMultiTask.h
Middleware\ST\STM32_USB_Device_Library\Class\CDC\Src\usbd_cdc.c
● Additional info, page 294
o In the IDE, some files are greyed and have a strike through them. This indicates they are not included in the current build configuration.
o The screen-shot below shows an example. The active build-configuration is rawCDC, and VirtualCommDriver.c is not included in it.
● Clarification, page 294:
o The code shown in the book differs from the code provided in the repo.
o From the repo, usbPrintOutTask() has a two calls to vTaskDelay(100), whereas the book just has one.
o When running the code from the repo, the output is not missing "message" lines, unlike what is shown on page 295.
● Additional info, page 294:
o Some of the USB-related functions have a suffix "_FS", e.g., CDC_Transmit_FS().
o "_FS" stands for "full-speed".
o USB acronyms are specified in , Reference manual, STM32F76xxx and STM32F77xxx advanced Arm-based 32-bit MCUs, in section 41, "USB on-the-go full-speed/high-speed"
o Other examples:
■ LS : Low-speed
■ HS : High-speed
■ OTG : On-the-go
● Tip, page 295
o On Windows, Tera Term's line-feeds need to be configured.
o In usbPrintOutTask(), lf is sent for "\n".
o To configure Tera Term:
■ Setup : Terminal : Receive : LF
● Clarification, page 299
o The code added to usbd_cdc.c is in the function USBD_CDC_DataIn().
■ USBD_CDC_DataIn() gets called within a USB ISR. So, the function pointed to by hcdc->TxCallBack must be ISR-safe. This is further explained on pages 302 and 305.
o The call-chain for USBD_CDC_DataIn() might be:
■ HAL_PCD_IRQHandler() calls
● (Note: Handles PCD interrupt request; PCD is Peripheral Control Driver)
■ (Note: these calls are made after the transmission is sent:)
■ HAL_PCD_DataInStageCallback() calls
■ USBD_LL_DataInStage() calls
■ pdev->pClass->DataIn() which is USBD_CDC_DataIn()
o References:
■ Call-chain
● https://community.st.com/s/question/0D50X00009XkZZi/stm32cubehal-usb-cdc-tx-complete-callback
■ User Guide : Description of STM32F7 HAL and low-layer drivers
● https://www.st.com/en/embedded-software/stm32cubef7.html#documentation
■ STM32 USB tutorial
● On this article, you find application examples, document references, tips and tricks and so on related to STM32 USB
● https://wiki.st.com/stm32mcu/wiki/USB_overview
● Clarification, page 300
o VirtualComDriver.c includes the function GetUsbRxStreamBuff() and the stream-buffer vcom_rxStream. They aren't used until Chapter 13.
● Bug in book and code (VirtualComDriver.c), page 300
o TransmitUsbDataLossy() uses xStreamBufferSendFromISR(), but it should use xStreamBufferSend(), with the parameter xTicksToWait set to 0.
int32_t numBytesCopied = xStreamBufferSend( txStream, Buff, Len, 0);
o TransmitUsbDataLossy() is called from a task, not from an ISR.
o From the FreeRTOS manual: "Use xStreamBufferSend() to write to a stream buffer from a task. Use xStreamBufferSendFromISR() to write to a stream buffer from an interrupt service routine (ISR)."
● Clarification, page 300
o VirtualCommInit() calls MX_USB_DEVICE_Init().
o MX_USB_DEVICE_Init() was described earlier, on page 294. It is used to initialize the entire USB device driver stack. I think MX_USB_DEVICE_Init() was generated by STM32CubeMX.
● Bug in book and code (VirtualCommDriver.c, mainUsbStreamBuffer.c), page 308
o Problem:
■ The CPU usage cannot be measured accurately due to overflows in SystemView.
o Solution:
■ SystemView ran without overflow, after applying these fixes
● Remove calls to SEGGER_SYSVIEW_PrintfHost()
● Turn-off the Ozone debugger before starting SystemView
o Use Ozone to load the program and start it
o Turn off the debugger via: Debug : Stop Debug Session
● Additional info, page 308
o From my tests, the CPU usage is a bit different than what is shown in the book. Though, my tests used the fixes described above, to avoid overflow in SystemView.
o My test, using the book's original code:
txStream = xStreamBufferCreate( txBuffLen, 1);
uint8_t numBytes = xStreamBufferReceive(txStream, usbTxBuff, txBuffLen, portMAX_DELAY);
o My test, using these modifications described in the book:
txStream = xStreamBufferCreate(txBuffLen, 500);
uint8_t numBytes = xStreamBufferReceive(txStream, usbTxBuff, txBuffLen, 100);
● Bugs in book, pages 307-308
o This paragraph, from the book, has some misstatements:
■ Decrease the maximum amount of time to wait on data to become available in the stream from an infinite timeout to 100 ticks. This minimizes context switching and how often usbTask will need to run. It also allows for more data to be transferred to the USB stack at a time:
■ The underlined sentences are incorrect. The original time-to-wait was portMAX_DELAY, and it has the potential to result in larger data transfers, and less context switches for usbTask.
o This sentence, from the book, has some misstatements:
■ Increasing the trigger value of the stream buffer from 1 to 500 bytes and increasing the available block time from 1 to 100 ticks reduces the CPU usage of usbTask by a whopping 94%:
■ The underlined phrase is incorrect. The block-time was decreased from portMAX_DELAY to 100. The decrease would most likely increase the CPU usage of usbTask.
o For a trigger-value of 500 bytes, my tests indicate the CPU usage is almost identical for block-times of 100 and portMAX_DELAY. The test for a block-time of 100 is shown above. The test for a block-time of portMAX_DELAY is shown below.
■ My test, using this modified code:
txStream = xStreamBufferCreate( txBuffLen, 500);
uint8_t numBytes = xStreamBufferReceive(txStream, usbTxBuff, txBuffLen, portMAX_DELAY);
● Clarification, page 309
o This paragraph was confusing to me:
■ To prevent multiple copies of this mutex from being created for each compilation unit VirtualComDriverMultitTask is included in, we won't define our private global variables as having static scope this time. Since we don't have namespaces in C, we'll prepend the names with vcom_ in an attempt to avoid naming collisions with other globals.
o The paragraph is describing VirtualCommDriverMultiTask.c, and its private global variables. The paragraph says those variables are defined in a way that is amenable for use in multiple compilation units. Apparently, those variables are:
uint8_t vcom_usbTxBuff[txBuffLen];
StreamBufferHandle_t vcom_rxStream = NULL;
StreamBufferHandle_t vcom_txStream = NULL;
TaskHandle_t vcom_usbTaskHandle = NULL;
SemaphoreHandle_t vcom_mutexPtr = NULL;
o In the paragraph, a contrast is made with VirtualCommDriver.c. That file's private global variables are defined as static. Apparently, those variables are:
static uint8_t usbTxBuff[txBuffLen];
static StreamBufferHandle_t txStream = NULL;
static TaskHandle_t usbTaskHandle = NULL;
o The paragraph is confusing because support for multiple compilation units isn't actually implemented in VirtualCommDriverMultiTask.c.
o For example, the private global variables would need to be defined in a header file. There, a conditional macro is needed to support the extern prefix. This use of header files is described here:
■ http://www.mathcs.emory.edu/~cheung/Courses/255/Syllabus/1-C-intro/cprep2.html