Using debugger swo on stm32F446RE, CubeIDE - stm32

As the title suggest I would like to use swo for debugging on an stm32 device without the use of st-link utils.I think I have flashed the code to send messages via swo on my chip but I can not establish a connection with the correct port as some tutorials suggested. I also set the SWV debugger clock rate correctly. I use SWV debugger to check output. The console shows "Download verified successfully", but swv returns nothing. The picture specifics about my configuration:
The SYS configuration shows conflict. I have tried both serial wire and Trace Asynchronous Sw. Is this a reason for the error?
Relative code on my main
while (1)
{
printf("Debug\r\n");
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
#include <stdio.h>
int __io_putchar(uint8_t ch)
{
return ITM_SendChar(ch);
}

Related

STM32L4 USB not appearing on computer as device

I have a STM32 Nucleo-64 development board with STM32L476RG MCU on it.. I have made a small PCB that, among other things, brings the USB interface to a connector.
I have followed the steps shown here: https://www.youtube.com/watch?v=rLnQ3W8gmjY
When I run the code in debug mode (in STM32CubeIDE v1.10.1) the USB never appears on my computer. I have also probed the USB data +/- signals and see no activity.
When I step through the code, I can see that something is failing immediately in:
MX_USB_DEVICE_Init()
USBD_Init()
The code the that fails is:
USBD_StatusTypeDef USBD_Init(USBD_HandleTypeDef *pdev,
USBD_DescriptorsTypeDef *pdesc, uint8_t id)
{
USBD_StatusTypeDef ret;
/* Check whether the USB Host handle is valid */
if (pdev == NULL)
{
#if (USBD_DEBUG_LEVEL > 1U)
USBD_ErrLog("Invalid Device handle");
#endif
return USBD_FAIL;
}
The exact line above that fails is if (pdev == NULL)
One thing to note is that the CubeMX tool did NOT add a handler declaration:
USBD_HandleTypeDef hUsbDeviceFS;
...despite me configuring up the USB interface... I added my own line in main.c:
extern USBD_HandleTypeDef hUsbDeviceFS;
..thinking it may be declared elsewhere??
Can someone please help me figure out whats going on?
Thanks!
Followed a video example online, but its not working as expected. I was expecting to see the dev board appear as a USB device on my computer and spit out some text.

Sending data over UART from a buffer filled by DMA

I have an ADC set up with DMA to fill a buffer in circular mode. I've verified with the debugger that this buffer is being filled with the expected data.
I am using a FreeRTOS task to send this data over UART based on the interrupts provided by the DMA functionality. When the buffer is half full, I send the first half; when the buffer is full, I send the second half.
I am using a Nucleo L476RG.
Here is my code:
#include "ADC.hpp"
#include <string.h>
#include "FreeRTOS.h"
#include "semphr.h"
#include "task.h"
#include "main.h"
#include "utils/print.hpp"
#include "stm32l4xx_hal.h"
extern ADC_HandleTypeDef hadc3;
extern UART_HandleTypeDef huart2;
extern volatile SemaphoreHandle_t print_lock;
namespace ADC
{
volatile SemaphoreHandle_t adc_lock;
volatile uint16_t adc_buf[ADC_BUF_SIZE];
volatile uint8_t buf[] = "abcdefg\r\n";
void task(void *arg)
{
adc_lock = xSemaphoreCreateBinary();
HAL_ADC_Start_DMA(&hadc3, (uint32_t *)adc_buf, ADC_BUF_SIZE);
HAL_StatusTypeDef result;
uint16_t offset = ADC_BUF_SIZE >> 1;
while (1)
{
xSemaphoreTake(adc_lock, HAL_MAX_DELAY);
offset = (offset + (ADC_BUF_SIZE >> 1)) % ADC_BUF_SIZE;
xSemaphoreTake(print_lock, HAL_MAX_DELAY);
while ((result = HAL_UART_Transmit(&huart2, (uint8_t *)adc_buf+offset*2, ADC_BUF_SIZE, HAL_MAX_DELAY)) == HAL_BUSY) {}
xSemaphoreGive(print_lock);
}
vTaskDelete(nullptr);
}
} // namespace ADC
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc)
{
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
xSemaphoreGiveFromISR(ADC::adc_lock, nullptr);
}
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
xSemaphoreGiveFromISR(ADC::adc_lock, nullptr);
}
Here is a screenshot from the debugger showing correct data in adc_buf
When looking at the received data using screen /dev/ttyACM0 115200, then converting to hex using vscode, this is what is received. I have already verified that the baudrate is correct.
I've tried adding a buffer with a long string message and sending that over and over, and it is sent and received correctly. Only data from the DMA buffer is being sent as 0xFD rather than the correct bytes. All other data is sent and received correctly.
Here are the settings for the UART and the ADC/DMA.
When looking at the received data using screen /dev/ttyACM0 115200, then converting to hex using vscode, this is what is received.
Rather than perform an extra conversion step, suggest that you use a better tool such as minicom, which has a built-in hex display mode.
Addendum
Switching to minicom fixed it!
So apparently there's an issue when you perform the conversion "using vscode".
This result is consistent with your other testing of "adding a buffer with a long string message and sending that over and over, and it is sent and received correctly."
In hindsight, the next step in your testing could have been to perform the same conversion "using vscode" on this text data. Presumably you would not get the expected ASCII code values, and would then suspect that this conversion step was faulty.
It's being sent from the USB-A port on the Nucleo, so maybe that's why it's ttyACM0?
Yes. That is a USB-to-USB connection using CDC ACM, a protocol that can be used for emulating serial ports over USB. The PC is the USB host (as always), and the Nucleo board is a USB gadget implementing a virtual COM port.
There is no (actual) UART or USART involved with such a USB connection, so you are not "send[ing] this data over UART", nor is the USART2 Mode and Configuration relevant.
When your Nucleo program uses the HAL to access the huart2 pseudo-device, apparently this third "UART" is the virtual COM port using the USB connection. Assuming that the huart2 pseudo-device refers to the third USART device, USART2, is incorrect.

I2C transmit with DMA and HAL not working

This seems to be a problem that is somewhat common, but I have been unsuccessful with any of the solutions I have found online. Specifically I am trying to transmit a 1024 byte buffer (full 128x64 px image) to a SSD1306 display via I2C/DMA and the HAL generated in cubeIDE. I am using a STML432 nucleo board. I have no problem transmitting the buffer without DMA using HAL_I2C_Mem_Write
Based on other questions I have seen, the problem lies in the fact that the DMA finishes while the I2C bus is still working on the transmit. I just don't know how to remedy this and the examples given usually don't use the HAL (unfortunately, despite my efforts I am not quite competent to correctly apply them to the HAL myself I guess). I have tried using the interrupts for I2c and DMA with no luck, only about the first 254 bytes get transferred (just shy of two rows showing on the screen).
Here is my code for sending the buffer:
static void ssd1306_WriteMData_DMA(const uint8_t *data, uint16_t size)
{
while(HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY);
HAL_I2C_Mem_Write_DMA(&hi2c1, I2C_ADDR, SSD1306_REG_MDAT, 1, (uint8_t*)data, size);
}
and the code for each interrupt handler:
void I2C1_EV_IRQHandler(void)
{
/* USER CODE BEGIN I2C1_EV_IRQn 0 */
if(I2C1->ISR & I2C_ISR_TCR){
I2C1->CR2 |= (I2C_CR2_STOP);// stop i2c
I2C1->ICR |= (I2C_ICR_STOPCF);// Reset the ICR flag.
// stop DMA
DMA1->IFCR |= DMA_IFCR_CTCIF6;
// clear flag
DMA1_Channel6->CCR &= ~DMA_CCR_EN;
}
/* USER CODE END I2C1_EV_IRQn 0 */
//HAL_I2C_EV_IRQHandler(&hi2c1);
/* USER CODE BEGIN I2C1_EV_IRQn 1 */
/* USER CODE END I2C1_EV_IRQn 1 */
}
void DMA1_Channel6_IRQHandler(void)
{
/* USER CODE BEGIN DMA1_Channel6_IRQn 0 */
// stop DMA
DMA1->IFCR |= DMA_IFCR_CTCIF6;
// clear flag
DMA1_Channel6->CCR &= ~DMA_CCR_EN;
/* USER CODE END DMA1_Channel6_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_i2c1_tx);
/* USER CODE BEGIN DMA1_Channel6_IRQn 1 */
/* USER CODE END DMA1_Channel6_IRQn 1 */
}
I think that is all the pertinent code, let me know if there is something else I am missing. All of the initialization code for the peripherals was done through cubeMX, but I can post that if need be, or the settings. I feel like it is something really simple that I'm missing, but this is a bit over my head to be honest so I don't quite grasp exactly what's going on...
Thanks for any help!
Problem is in your custom DMA1_Channel6_IRQHandler and I2C1_EV_IRQHandler. Those functions will be called right after I2C transfers 255 bytes, which is MAX_NBYTE_SIZE for NBYTES. HAL already have all required interrupt routines inside stm32l4xx_hal_i2c.c:
Sets I2C transfer IRQ handler to I2C_Master_ISR_DMA;
Checks if data size is larger than 255 bytes and uses reload mode.
Sets I2C DMA complete callback to I2C_DMAMasterTransmitCplt;
Starts DMA using HAL_DMA_Start_IT()
Configures I2C registers using I2C_TransferConfig()
HAL driver will handle all I2C+DMA interrupts using I2C_Master_ISR_DMA and I2C_DMAMasterTransmitCplt:
I2C_DMAMasterTransmitCplt will restart DMA for each chunk of 255 (MAX_NBYTE_SIZE) or less bytes.
I2C_Master_ISR_DMA will reset RELOAD/NBYTES registers using I2C_TransferConfig.
For last block of data I2C_AUTOEND_MODE is used.
So all you need is
remove "user code" from DMA1_Channel6_IRQHandler and I2C1_EV_IRQHandler functions
enable I2C1 event interrupt in STM32 Device Configuration Tool
configure DMA with data width byte/byte
perform a single call of HAL_I2C_Mem_Write_DMA(...) to start transfer
check HAL_I2C_STATE_READY before next transfer
See HAL_I2C_Mem_Write_DMA, I2C_Master_ISR_DMA and I2C_DMAMasterTransmitCplt source code in stm32l4xx_hal_i2c.c to understand how it works.
About why DMA finishes while I2C is still working: HAL driver sends I2C data over DMA using 255 byte chunks, stops DMA, starts DMA, clears I2C_CR2 NBYTES/RELOAD, enables DMA. DMA may be run continuously using DMA_CIRCULAR mode, but currently it is not implemented in HAL I2C drivers. Here is example of using I2C with DMA_CIRCULAR mode:
// DMA enabled single time
hi2c1.hdmatx->XferCpltCallback = MY_I2C_DMAMasterTransmitCplt;
HAL_DMA_Start_IT(hi2c1.hdmatx, (uint32_t)&i2cBuffer, (uint32_t)&hi2c1.Instance->TXDR, I2C_BUFFER_SIZE);
MY_I2C_TransferConfig(&hi2c1, (uint16_t)DAC_ADDR, 254, I2C_RELOAD_MODE, I2C_GENERATE_START_WRITE); // in first call using I2C_GENERATE_START_WRITE
uint32_t tmpisr = I2C_IT_TCI;
__HAL_I2C_ENABLE_IT(&hi2c1, tmpisr);
hi2c1.Instance->CR1 |= I2C_CR1_TXDMAEN;
Still need to clear I2C_CR2 NBYTES/RELOAD using MY_I2C_TransferConfig each 254 bytes (I do not use 255 to align interrupt firing to even index in array):
static HAL_StatusTypeDef MY_I2C_Master_ISR_DMA(struct __I2C_HandleTypeDef *hi2c, uint32_t ITFlags, uint32_t ITSources)
{
if (__HAL_I2C_GET_FLAG(&hi2c1, I2C_FLAG_TCR) == SET)
{
MY_I2C_TransferConfig(&hi2c1, (uint16_t)DAC_ADDR, 254, I2C_RELOAD_MODE, I2C_NO_STARTSTOP); // in repeated calls using I2C_NO_STARTSTOP
}
return HAL_OK;
}
With this approach DMA circular buffer size is not limited to 255 bytes:
#define I2C_BUFFER_SIZE 1024
uint8_t i2cBuffer[I2C_BUFFER_SIZE];
Main.c should have MY_I2C_TransferConfig() function, which is copy pasted version of private function HAL_I2C_TransferConfig() from stm32l4xx_hal_i2c.c. On earlier STM32 microcontrollers there is no NBYTES/RELOAD fields and I2C_CR2 does not need to be updated this way.
Using DMA in circular mode allows to achieve highest frame rate, you just need to fill DMA buffers in time using XferHalfCpltCallback and XferCpltCallback callbacks. Frames may be copied from larger buffer by using memcpy() or DMA MEMTOMEM transfer.
You haven't said which STM32 you are using. They have different bit definitions (because the I2C peripherals in the earlier released parts were rubbish) but it looks like you are using one of the later ones.
Basically you can find what you need in the bit definitions for the I2C registers in the reference manual. If you are setting stop before it has finished you need to look for a BUSY bit that gets cleared or BTF (byte transfer finished) bit that gets set when it is time for you to send stop.

2 STM32 boards with SPI

2 STM32 μc (NucleoF767ZI and Nucleo F446RE) should communicate via SPI. The first µc is programmed with Simulink using the Nucleo Support Package. As it stands, the μc with the Support Package can only work as a master. Now I just want to send a number from 0-255 to the slave μc for testing. And see the message with debugging mode. According to the Simulink block parameter, the Slave address register must be entered.
Then i am going to measure the the Duty Cycle of a PWM signal and send to via spi to the Master µc in Simulink, so the µc will function as a Sensor.
/* USER CODE BEGIN 0 */
uint8_t Rx[2];
/* USER CODE END 0
/* USER CODE BEGIN 2 */
__HAL_SPI_ENABLE(&hspi1);
/* USER CODE END 2 */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_SPI_Receive(&hspi1,Rx,1,10);
HAL_Delay(50);
}
/* USER CODE END 3 */
}
So my question, is it possible that my SPI of the slave µc (e.g., SPI2) has an address?
sIMULINK-SPI

Resetting I2C state using HAL in STM32L0 MCU

I use I2C-tools to test firmware (HAL-based), I2C, STM32L0 MCU. When I send command to MCU (via i2cset utility), it sends an answer (received in i2cget). It works fine. If I call i2cget twice after single i2cset, it fails (which is expected behaviour). But if I execute i2cset after that error, then it also fails. So, the receive-transfer becomes broken (no callback is activated). How can it be fixed?
At the moment, HAL_I2C_Slave_Receive_IT() is called in HAL_I2C_SlaveTxCpltCallback(). HAL_I2C_SlaveRxCpltCallback() calls HAL_I2C_Slave_Transmit_IT(). Should I put HAL_I2C_Slave_Receive_IT() in two callbacks (receive/transmit related)?
I don't know if you've solved this question. However, it is more accurate to define a flag that states that the HAL_I2C_SlaveTxCpltCallback, HAL_I2C_SlaveRxCpltCallback, and HAL_I2C_ErrorCallback functions have completed transfers or an error occurred.
maybe the following codes may be useful. You can reinit after making deinit.
/**
* #brief Initialize and setup GPIO and I2C peripheral
* #param obj : pointer to i2c_t structure
* #retval none
*/
void i2c_deinit(i2c_t *obj)
{
HAL_NVIC_DisableIRQ(obj->irq);
#if !defined(STM32F0xx) && !defined(STM32L0xx)
HAL_NVIC_DisableIRQ(obj->irqER);
#endif // !defined(STM32F0xx) && !defined(STM32L0xx)
HAL_I2C_DeInit(&(obj->handle));
}
void LDC_I2C_ReInit(void)
{
HAL_I2C_Init(&hi2c1);
}
and it has a fine example in these links.
https://github.com/stm32duino/Arduino_Core_STM32/blob/c392140415b3cf29100062ecb083adfa0f59f8b1/cores/arduino/stm32/twi.h
https://github.com/stm32duino/Arduino_Core_STM32/blob/c392140415b3cf29100062ecb083adfa0f59f8b1/cores/arduino/stm32/twi.c