USART to 4MBps! how? STM32L151xx - c

How can I increase the USART baud rate to 2Mbps, 3Mbps or 4Mbps. I am using STM32L151RCT6A, I am able to run to 921600. I have set clock with PLL 32MHz. On the datasheet it is given, which shows it is possible, Has anyone ever done this?

The datasheet only outlined the specific part and its peripheral set and electrical characteristics. For information on how to use the device you need the Reference Manual. This gives the following equation for baud rate:
Tx/Rx baud = CK_APB1 / (8 x (2 - OVER8) x USARTDIV)
Where USARTDIV is an unsigned fixed point number that is coded on the USART_BRR register.
When OVER8=0, the fractional part is coded on 4 bits and programmed by the
DIV_fraction[3:0] bits in the USART_BRR register
When OVER8=1, the fractional part is coded on 3 bits and programmed by the
DIV_fraction[2:0] bits in the USART_BRR register, and bit DIV_fraction3 must be kept
cleared.
The USARTs are on the APB1 bus, Figure 12 in the reference manual is the clock tree, which shows how the APB1 clock is derived from the PLL clock. The maximum APB1 clock is 32MHz. OVER8=1 is required for higher speeds, giving:
baud = 32X106 / (USARTDIV x 8).
So USARTDIV = 32X106 / (baud x 8)
For 4Mbps therefore, USARTDIV=1 (see table 138 S.No.12 for details). For 2Mps, USARTDIV=2. To achieve 3Mbps you will have to reduce the APB1 clock to 24MHz and set USARTDIV=1 (see table 131). But note that the clock rate changes for all other APB1 peripherals too.
The simplest way to correctly program the USART baud rate is via the STM32L1xx standard peripheral library. Also to determine the correct peripheral clock settings (and more), and generate initialisation code, you can use STM's MicroXplorer tool.

Related

Issue in interfacing E-Ink display with STM8S103F3P6 microcontroller

I am using Waveshare 1.54" ePaper Module. Using SPI peripheral:
CPU freq is 16Mhz
SPI Prescaler DIV by 8
MSB FIRST
CPOL=0, CPHA=1
The Display does not response but it respond with TI CC1310 properly.
The problem with SPI is after transmitting byte it does not go to ideal high state.
I have checked with logic analyser.
The SPI is initialised thus:
/****************** Initializing The SPI Peripheral ******************/
void SPI_setup(void)
{
CLK_PeripheralClockConfig(CLK_PERIPHERAL_SPI, ENABLE); //Enable SPI Peripheral Clock
//Set the MOSI, MISO and SCk at high Level.
//GPIO_ExternalPullUpConfig(GPIOC, (GPIO_Pin_TypeDef)(GPIO_PIN_6),ENABLE);
SPI_DeInit();
SPI_Init(SPI_FIRSTBIT_MSB, //Send MSB First
SPI_BAUDRATEPRESCALER_8, //Fosc/16 = 1MHz
SPI_MODE_MASTER,
SPI_CLOCKPOLARITY_LOW, //IDEAL Clock Polarity is LOW
SPI_CLOCKPHASE_2EDGE, //The first clock transition is the first data capture edge
SPI_DATADIRECTION_2LINES_FULLDUPLEX, //Only TX is Enable
SPI_NSS_SOFT,
0x00);
SPI_Cmd(ENABLE);
}
This is pretty much the same problem you had at Issue in interfacing SPI e-ink display with PIC 18F46K22 only on a different processor. Worth noting that CPHA on STM8 has the opposite sense to CPE on PIC18 which may be the cause of your error. That is to say that CPHA=1 on the STM8 has the same effect as CKE=0 on the PIC18. You really have to look at the timing diagrams for each part carefully.
From https://www.waveshare.com/wiki/1.54inch_e-Paper_Module:
Compare with the STM8 reference manual:
Clearly you need one of:
CPHA=1 / CPOL=1 (SPI_CLOCKPOLARITY_HIGH / SPI_CLOCKPHASE_2EDGE) or
CPHA=0 / CPOL=0 (SPI_CLOCKPOLARITY_LOW / SPI_CLOCKPHASE_1EDGE)
If it is the SCLK that you want to be normally-high, then you need the first option - although I fail to see why that is "ideal", the Waveshare diagram clearly indicates that either is acceptable.

STM32 Difference between Max interface clock and max timer clock

I am using TIM1 on a H743ZI with 3 PWM channels.
I am trying to maximize the PWM resolution so I need to maximize the clock speed on TIM1.
the datasheet (screenshot below) gives 120MHz and 240MHz values for Max interface clock and Max timer clock.
What is the difference between the 2? I have the clocks setup as shown below, with 120MHz on APB2's peripheral clocks and 240MHz on APB2's Timer clocks.
I need a 24KHz frequency on the PWM channels so I set the ARR to 4999 which confirms the H743 is using the 120MHz value (and not the 240MHz one).
Is it because the I am using the timer in a hardware related manner - hence the "peripheral clock"?
of course, my follow up question, would be whether or not I could use the HRTIM instead?
Every timer consists of the counter which is fed by the timer clock and the control unit which is responsible for interfacing with the bus (core and another peripherals) which is fed by the interface clock.
More general all peripherals have a digital control part. This part is fed by the bus clock (the bus the particular peripheral is connected to). Many peripherals have more than one clock - for example ADC where the digital controller form the bus clock, and the analogue part fed from another clock source.

Changing clock frequency on STM32 without impacting peripherals?

I'm a bit lost with STM32L486 clock management.
I want to change the clock frequency at run-time. Typically I want to be in Low-Power Run/Sleep mode most of the time, and at full frequency the rest of the time.
I know how to set up SysClk either at 80MHz using PLL or at 1MHz using MSI for example.
However the problem is that changing Sysclk is messing up most peripherals setup. For example the USART is not working anymore if I change the clock.
Is it a common practice to do that ( changing the frequency at runtime ) ?
The peripherals I need to use are: LPTIM ( no problem since they can be clocked independantly from SysClk ), ADC, AES accelerator, USART, TIM, SPI.
On STM32L4xx it is not so hard, if you look on "Clock tree" figure in datasheet, many peripherals which are clock dependent (USART, LPTIM, I2C, ..) can be driven with other clock sources than BUS clock, there is also possible to use LSE or internal HSI.
Although internal HSI is not crystal controlled is from my experience enough accurate for UART, also in bigger range of temperatures, but you can tune frequency of this oscillator by comparing its frequency with an external and more accurate clock during runtime, or use auto-buadrate detection.

PWM DMA to a whole GPIO

I've got an STM32F4, and I want to PWM a GPIO port that's been OR'd with a mask..
So, maybe we want to PWM 0b00100010 for awhile at 200khz, but then, 10khz later, we now want to PWM 0b00010001...then, 10kHz later, we want to PWM some other mask on the same GPIO.
My question is, how do you do this with DMA? I'm trying to trigger a DMA transfer that will set all the bits on a rising edge, and then another DMA transfer that will clear all the bits on a falling edge.
I haven't found a good way to do this, (at least with CubeMX and my limited experience with C & STM32's) as it looks like I only get a chance to do something on a rising edge.
One of my primary concerns is CPU time, because although I mention hundreds of kilohertz in the above example, I'd like to make this framework very robust in-so-far as it isn't going to be wasteful of CPU resources...That's why I like the DMA idea, since it's dedicated hardware doing the mindless lifting of a word here to a word there type of stuff, and the CPU can do other things like crunch numbers for a PID or something.
Edit
For clarity : I have a set of 6 values that I could write to a GPIO. These are stored in an array.
What I'm trying to do is set up a PWM timer to set the GPIO during the positive width of the PWM and then I want the GPIO to be set to 0b00000000 during the low period width if the pwm.
So, I need to see when the rising edge is, quickly write to the gpio, then see when the falling edge is, and write 0 to the gpio.
Limited solution without DMA
STM32F4 controllers have 12 timers with up to 4 PWM channels each, 32 in total. Some of them can be synchronized to start together, e.g. you can have TIM1 starting TIM2, TIM3, TIM4 and TIM8 simultaneously. That's 20 synchronized PWM outputs. If it's not enough, you can form chains where a slave timer is a master to another, but it'd be quite tricky to keep all of them perfectly synchronized. Not so tricky, if an offset of a few clock cycles is acceptable.
There are several examples in the STM32CubeF4 library example projects section, from which you can puzzle together your setup, look in Projects/*_EVAL/Examples/TIM/*Synchro*.
General solution
A general purpose or an advanced timer (that's all of them except TIM6 and TIM7) can trigger a DMA transfer when the counter reaches the reload value (update event) and when the counter equals any of the compare values (capture/compare event).
The idea is to let DMA write the desired bit pattern to the low (set) half of BSRR on a compare event, and the same bits to the high (reset) half of BSRR on an update event.
There is a problem though, that DMA1 cannot access the AHB bus at all (see Fig. 1 or 2 in the Reference Manual), to which the GPIO registers are connected. Therefore we must use DMA2, and that leaves us with the advanced timers TIM1 or TIM8. Things are further complicated because DMA requests caused by update and compare events from these timers end up on different DMA streams (see Table 43 in the RM). To make it somewhat simpler, we can use DMA 2, Stream 6 or Stream 2, Channel 0, which combine events from 3 timer channels. Instead of using the update event, we can set the compare register on one timer channel to 0.
Set up the DMA stream of the selected timer to
channel 0
single transfer (no burst)
memory data size 16 bit
peripheral data size 16 bit
no memory increment
peripheral address increment
circular mode
memory to peripheral
peripheral flow controller: I don't know, experiment
number of data items 2
peripheral address GPIOx->BSRR
memory address points to the output bit pattern
direct mode
at last, enable the channel.
Now, set up the timer
set the prescaler and generate an update event if required
set the auto reload value to achieve the required frequency
set the compare value of Channel 1 to 0
set the compare value of Channel 2 to the required duty cycle
enable DMA request for both channels
enable compare output on both channels
enable the counter
This way you can control 16 pins with each timer, 32 if using both of them in master-slave mode.
To control even more pins (up to 64) at once, configure the additional DMA streams for channel 4 compare and timer update events, set the number of data items to 1, and use ((uint32_t)&GPIOx->BSRR)+2 as the peripheral address for the update stream.
Channels 2 and 4 can be used as regular PWM outputs, giving you 4 more pins. Maybe Channel 3 too.
You can still use TIM2, TIM3, TIM4, and TIM5 (each can be slaved to TIM1 or TIM8) for 16 more PWM outputs as described in the first part of my post. Maybe TIM9 and TIM12 too, for 4 more, if you can find a suitable master-slave setup.
That's 90 pins toggling at once. Watch out for total current limits.
what PWM 0b00100010 means? PWM is a square wave with some duty ratio. it wil be very difficult to archive using DMA but you will need to have table with already calculated values. For example to have 2kHz PWM with 10% ratio you will need to have 10 samples one with bit set, nine with bit zeroed. You configure the timer to 20k / sec trigger mem-to-mem (GPIO has to be done this way) DMA transmission in the circular mode. On the pin you will have 2kHz 10% wave. The PWM resolution will be 10%. If you want to make it 0.5% you will need 200 samples table and DMA triggered 400k times per second.
IMO it is better to use timer and DMA to load new values to it (read about the burst DMA mode in the timer documentation in the Reference Manual)

Generate/ output clock pulse ( C code )

Im using Ethernut 2.1 B and I need a C program that outputs a clock signal at the timer 1 output B, with other words on output OCIB. The frequency of the clock signal should be at 1.0 kHz.
Anyone know how this could be done?
You need to look in COM bits for your timer. For instance, for Timer0 (8-bit), the COM bits are set in the TCCR0 register. Probably the setting you'd be interested in is
TCCR0 |= (0<<COM1)|1<<COM0); // Toggle OC0 on compare match
This will toggle the OC0 (pin14) line when timer reaches the specified value.
Which timer you use depends on the precision you need: obviosely the 16-bit timers can give you more precise time resolution then the 8-bit timers.
The setting of the registers for your specific frequency (1Khz) depends on the clock speed of your chip, and which timer you are using: the timers use a pre-scaled general clock signal (see table 56 of the datasheet for possible values). This means that the prescaler settings will depend on your clock speed, and how high you want to count. For most precision you will want to count as high as possible, which means the lowest possible prescaler setting compatible with your timer's maximum value.
As far as where to start, generally, reading the datasheet is a good place, but googling "AVR timer" can also be very helpful.
It seems to be based on the Atmel ATmega 128, so read that CPU's data sheet to figure out how to program the timer hardware.
Not sure if this microcontroller supports directly driving an output from a timer, if it doesn't you're going to have to do it in software from the interrupt service routine.

Resources