2021-09-05 12:34 AM
I'd love to see a well structured, non-HAL based STM32 peripheral driver that is actually working in a real world application. For my purposes, a H7 UART driver that uses DMA would be great. If it implemented idle character detect and/or character match, that would be icing on the cake. If someone could point me at an example like this on some public repository somewhere, or just copy an example in this thread, that would be great.
I'm not trying to re-start the HAL vs no-HAL debate, I'd just like to see a non-HAL implementation for educational purposes.
Thanks
2021-09-05 01:15 AM
Anything you'd deem to be a "driver" would suffer from the same fundamental problems than Cube/HAL - bloat and inflexibility. This is because the world of microcontrollers is incredibly complex, and there is almost an infinite number of ways how to use its individual elements. This is in contrast with the world of the "big computers" has/does: it goes for minimum variability, with almost only one single goal: brutal computing power. "Drivers"/"Abstraction" layers do what the world of "big computer" does: attempts to find the absolute minimum common denominator, inevitably crippling the rich hardware possibilities to a few "commonly used cases".
What you need instead of "drivers" are examples.
Now these are hard to produce for exactly the same reason why good documentation is hard to produce: they need a certain rare skillset, and they are incredibly expensive to produce.
Now what you ask for is not one example but five (six): enabling clocks in RCC, setting up GPIO, setting up DMA (in 'H7 also DMAMUX), setting up interrupts, and setting up and actually use the UART. I could come up with something (and I have in some cases, although not in the quality you and I would be comfortable with), but I don't use 'H7, I am not interested in 'H7, as 'H7 is unnecessary complex and not that useful for typical micro*controller* applications. And I have to pay *my* bills.
JW
2021-09-05 05:40 AM
@Community member You're correct, I'm looking for a complete example not just a driver. But I don't want anyone to generate some theoretical example for me. I was hoping (still am) that somebody has an already existing, open source, real world project on Bitbucket or Github or something like that they could point me at. It doesn't have to be perfect, just has to be working and I'd probably still be able to learn a lot.
I'm curious why you say the H7 is unnecessarily complex to the point you don't use it. I've been running into complexity issues myself like getting the STM32 UART DMA example to run with character match and idle detection on the H7A3 Nucleo board using USART2 but not being able to get it working on the H7B3 Discovery on UART4. HAL makes a simple change like that so complex it is frustrating but I'm still working on it. But, I kind of like it because it has about the same power consumption as the F413 for example at 2.8X the clock rate and my system needs to run on battery power for a year (we hope). And the low power UART and low power timer may be useful in my app and it has features like character match on the UARTs.
2021-09-05 06:38 AM
The appeal of the H7 series is the double precision floating point and the 280, 400, 480, 550 MHZ type options, although for the most part that's faster than a lot of things need. At some point you get into a place where the infrastructure and memory behind Embedded Linux gets to be more appealing.
2021-09-05 08:31 AM
Well, I've just recently posted a small and simple example. UART continuous receive with interrupts, for STM32H7.
Cleaned-up summary from this thread. (Again thanks to ST support for helping me to fix it).
Most of initialization of the UART is borrowed from Cube-generated code. If there's enough code memory, there's no pressure to get rid of it immediately.
Note how the interrupt handler is smaller and faster than one provided in the HAL - but it is restricted exactly to my application: no support for 9-bit characters, no error detection.
Instead of "idle" detection, here I use Receive Timeout (RTO) which is better suited for my application.
Instead of providing a buffer to store received bytes, I pass them immediately to a custom function. So the receive never ends and runs continuously.
Transmit here can be done either with polling functions, or the interrupt driven path can be added later.
// INIT
void UART_init(UART_HandleTypeDef *pu, USART_TypeDef *U, unsigned baud_rate)
{
memset(pu, 0, sizeof(UART_HandleTypeDef ));
pu->Instance = U;
pu->Init.BaudRate = baud_rate;
pu->Init.WordLength = UART_WORDLENGTH_8B;
pu->Init.StopBits = UART_STOPBITS_1;
pu->Init.Parity = UART_PARITY_NONE;
pu->Init.HwFlowCtl = UART_HWCONTROL_NONE;
pu->Init.Mode = UART_MODE_TX_RX;
if (HAL_UART_Init(pu) != HAL_OK)
Error_Handler();
//Enable RTO
HAL_UART_ReceiverTimeout_Config(pu, 4 *10); // RTO, in bit times ~ 4 bytes
HAL_UART_EnableReceiverTimeout(pu);
HAL_UARTEx_SetTxFifoThreshold(pu, UART_TXFIFO_THRESHOLD_3_4);
HAL_UARTEx_SetRxFifoThreshold(pu, UART_RXFIFO_THRESHOLD_1_2);
if (HAL_UARTEx_EnableFifoMode(pu) != HAL_OK)
{
Error_Handler();
}
// Enable the UART RX FIFO Threshold interrupt and Receiver Timeout Interrupt
SET_BIT(TmpInstance->CR3, USART_CR3_RXFTIE);
SET_BIT(TmpInstance->CR1, USART_CR1_RTOIE);
HAL_NVIC_SetPriority(USART1_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
}
// ISR for USART1
void USART1_IRQHandler()
{
USART_TypeDef *Instance = USART1;
uint32_t isrflags = READ_REG(Instance->ISR);
if (isrflags & USART_ISR_RTOF) {
Instance->ICR = UART_CLEAR_RTOF;
}
if (isrflags & USART_ISR_ORE) {
Instance->ICR = UART_CLEAR_OREF; //TODO: log overrun
}
while ((isrflags & USART_ISR_RXNE_RXFNE) != 0U)
{
uint32_t udata = READ_REG(Instance->RDR);
usart_rx_handler(udata); // consume received bytes
isrflags = READ_REG(Instance->ISR);
}
/* check TX interrupts if enabled... */
}
Examples of UARTs with DMA by Tilen Majerle are here.
2021-09-05 10:14 AM
@Pavel A. I'm putting both your example above and the other thread you link to in my reference library. Thanks.
2021-09-05 10:27 AM
WRT the H7, the obvious win for me is the relatively low power at 280 MHz and other low power features. At this point, I'm hoping I've got enough of the peripheral infrastructure working that I can concentrate on the fun part: implementing the functionality required to get research quality data in the ocean. We measure temperature to a couple of milli-degrees C, salinity, pressure, pH to less than 0.01 pH units, Nitrate, oxygen, optical radiation, chlorophyll and transmissivity which is challenging to say the least.
WRT Linux, several of the projects at my company use embedded Linux. They usually have a team of several very experienced SW engineers and even then they regularly tear their hair out trying to solve Linux problems. One of the scariest thinks you can hear around my company with respect to SW is "Oh no, I have to hack my Linux kernel again". I'm a team of one ocean engineer with very little SW experience and a uncharacteristically optimistic belief that I can pull this off with the kind of help I get on this forum.