I want to transmit 4 Bytes of data periodically with TIM_UP DMA. i.e when a timer update occurs (or Timer overflows), timer DMA send 4 Bytes with UART. Could someone help me?
Related
For educational purpose (I'm new in this area), I'm trying to write a driver for the AD7124 ADC, connected to the SPI serial interface of a Raspberry PI4, running under Raspbian with a kernel v5.4 on which I applied a RT patch.
This ADC has a continuous read mode in which the readiness of a new sample is signalled by the lowering its (DOUT/!RDY) pin.
In addition to it being connected to the MISO pin, my idea was to connect it to a GPIO pin of the Raspi, in order to raise an interrupt for each new sample, triggered by the lowering of the DOUT/!RDY pin.
The issue is that the SPI read done in my interrupt fires a new interrupt, as seen in the capture from an oscilloscope (https://i.stack.imgur.com/BJnbO.png), connected to the DOUT/!RDY pin (in yellow), and the clock signal of the SPI interface (in purple).
The SCLK signal is triggered by the SPI read, and we can see that two reads are triggered for only one ready sample.
Below, how I request the IRQ in the probe proc :
// Getting the interrupt GPIO pin
padpvd->pgpio_desc = devm_gpiod_get (&spi->dev, AD7124_GPIO_NAME, GPIOD_IN ) ;
if (IS_ERR(padpvd->pgpio_desc)) {
...
}
// Getting the interrupt number
padpvd->irq = gpiod_to_irq(padpvd->pgpio_desc);
if (padpvd->irq < 0) {
...
}
In an IOCTL start routine, after having started the ADC, I request the IRQ :
ret = request_threaded_irq ( padpvd->irq, NULL, ad7124_threaded_irq_handler,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
THIS_MODULE->name, padpvd->ad7124_spi_dev ) ;
In the handler, I do not do much more than reading the data using an spi_sync() call, and storing it in a buffer, before returning IRQ_HANDLED.
So the question is: why do the signals generated on my GPIO PIN by the SPI transfer fire an interrupt while I used the IRQF_ONESHOT flag ?
ST has some application notes that talk about emulating a parallel bus using DMA to GPIO. I appreciate that, but it doesn't answer important questions. I am looking through the reference manual, and I can't seem to find clarify the things that I am concerned about.
I am most concerned about the jitter. The reference manual repeatedly states, that when DMA is triggered (e.g., by a timer), the DMA controller will read the memory and transfer the value to the peripheral. That might be fine with peripherals that have their own FIFO. There, when space is available in the FIFO, DMA is triggered and fills the FIFO. That will probably happen before the FIFO runs empty.
But with GPIO, if the DMA channels doesn't have a FIFO itself, the data will not be ready when the timer triggers and it needs to be fetched from SRAM. So between the timer triggering and between the value actually arriving in the GPIO output register, some time may pass. This might be measurable when looking at the clock output by the timer and the GPIO pins. The DMA controller has to compete for access to the SRAM with the running program, so certain activities by the program may increase the jitter.
Maybe that is a colossal oversight on my part, but ST's reference manual doesn't seem mention a FIFO as part of the DMA. If that is the case, that would result in jitter which may impact performance at higher frequencies.
I need to toggle 3 to 4 pins synchronously to a clock from 100kHz to 1MHz. I am considering DMA to GPIO and also abusing a QuadSPI controller. I am currently testing on a STM32L4 but I'm also considering STM32F4 or even F1.
DMA to/from GPIOit is just memory-to-memory transfer. Many STM32 uCs have built in DMA FIFOs - but they will have not use here.
The core has always priority over the DMA so if it can be the issue (very unlikely) place the core accesible data (this data which uC will access when DMA is active in the separate memory area - for example CCM (if your uC has one)
Answering the question
memory to/FROM GPIO is very reliable - I personally did not have any problems with it.
If your clock can be anything between 100 kHz and 1 MHz, I guess you're not worried about jitter in the clock itself, only jitter in the data versus the clock. If your clock need not be continuous, a novel idea then is to do some preprocessing of the data to include the clock signal as part of the GPIO data. Then you could trigger the DMA at regular intervals using a timer, and you'll get the data frequency on the bus at half that rate with perfect alignment between clock and data.
So if you you want to send the four-bit data 5 6 B D with data valid on the positive clock edge, prepare the DMA buffer as so: 05 15 06 16 0B 1B 0D 1D and connect the GPIO pin 4 as the clock. Leave a final byte in the buffer to reset the clock/bus to idle state, if you need.
You can of course extend the idea and incorporate control signals such as chip selects and tri-state signals for external buffers, if needed.
Also take note that not all DMA blocks may have access to the AHB bus which is holding the GPIO registers. For example on STM32F40x, only DMA2 can be used (this is what got me, until I read this answer https://stackoverflow.com/a/46619315/6552613).
I haven't fully explored this space yet, but, by disabling interrupts and polling for interrupt flags in my main loop, it's made the jitter on my GPIO DMA basically disappear! Granted it might just be the set of interrupts have enabled, but everything down to the systick timer was killing me. By polling the interrupts in the main loop it seems to have fixed my issue.
Note that this is on an STM32F042, and I never exceed 6 MHz for my period. When I try to, i.e. try to go to 8 MHz sampling out, everything falls apart. YMMV
I read that the driver for "Software PWM" is running somehow on the PWM-HW and acessing all GPIOs without using the CPU. Can someone explain how that works? Is there a second processor in the Raspberry Pi used for PWM and PCM module(is there a diagram for the blocks)?
The question is related to this excellent driver which I used a lot in my robots.
Here is the explanation, which I unfortunately don't understand...
The driver works by setting up a linked list of DMA control blocks with the
last one linked back to the first, so once initialised the DMA controller
cycles round continuously and the driver does not need to get involved except
when a pulse width needs to be changed. For a given period there are two DMA
control blocks; the first transfers a single word to the GPIO 'clear output'
register, while the second transfers some number of words to the PWM FIFO to
generate the required pulse width time. In addition, interspersed with these
control blocks is one for each configured servo which is used to set an output.
While the driver does use the PWM peripheral, it only uses it to pace the DMA
transfers, so as to generate accurate delays."
Is the following understanding right:
The DMA controller is like a second processor. You can run code on it. So it is used here to control all the Raspberry GPIO pins high/low states together with the PWM block. DMA Controller does this continously. There are probably more than one DMA controller in the Raspberry, so the speed of the OS Linux is not influenced much due to one missing DMA controller.
I don't understand how exactly DMA and PWM work together.
I recommend reading RPIO source code together with ServoBlaster's, as it's slightly simplified and can help understanding. Also very important: Broadcom's BCM2835 manual which contains all the tiny details.
is there a diagram for the blocks
The manual contains all the functionalities offered by the chip (not in a block diagram though, as far as I’ve seen).
Is the following understanding right:
The DMA controller is part of the main chip (Broadcom, although I think the same happens on desktop CPUs). It can't exactly run code, but it can copy memory across peripherals by itself, without consuming the main processor’s time. The DMA controller has different channels which can copy memory independently and runs independently of the CPU.
It is configurable via "control blocks" (BCM manual page 40, 4.2.1.1): you can tell the DMA controller to first copy memory from A to B, then from C to D and so on.
don't understand how exactly DMA and PWM work together
DMA is used to send data to the PWM controller ("Pulse Width Modulator", BCM manual page 138, chap. 9), which consumes the data and this creates a very precise delay. Interestingly, the PWM controller is... not used to generate any PWM pulse, but just to wait.
Can someone explain how that works?
Ultimately, you configure the value of the GPIO pins (or the settings of the PWM or PCM generator), by setting memory at a special address; the memory in that region represents the peripheral configuration (BCM manual page 89, chapter 6).
So the idea is: copy 1 onto the memory that controls the GPIO pin value, using the DMA controller; wait the pulse width; copy 0 onto the GPIO pin value; wait the remaining part of the period; loop. Since the DMA controller does it, it doesn't consume CPU cycles.
The key point here is being able to make the DMA controller "wait" an exact amount of time, and for this, RPIO and ServoBlaster use the PWM controller in FIFO mode (the PCM generator also has such functionality, but let's stick to PWM). This means that the PWM controller will "send" the data it reads from its so-called FIFO queue, and then stop. It doesn't matter how it's "sent" (BCM manual page 139, 9.4 MSENi=0), the key point is that it requires a fixed amount of time. As a matter of fact, it doesn't even matter which data is sent: the DMA controller is configured to write into the FIFO queue and then wait until the PWM controller has finished sending data, and this creates a very precise delay.
The resolution of the resulting pulse is given by the duration of the PWM transfer, which depends on the frequency at which the PWM controller is running.
Example
We have a maximum resolution of 1ms (given by the PWM delay), and we want to have a pulse of 25% duty cycle with frequency 125Hz. The period of a pulse is thus 8ms. The DMA operation performed will be
Set pin to 1 (DMA write to GPIO mem)
Wait 1ms (DMA write to PWM FIFO)
Wait 1ms (DMA write to PWM FIFO)
Set the pin to 0 (DMA write to GPIO mem)
Wait 1ms (DMA write to PWM FIFO)
...repeat "Wait 1ms" 4 more times.
Wait 1ms (DMA write to PWM FIFO) and jump back to 1.
This will thus require at least 10 DMA control blocks (8 wait instructions, given by period / delay plus 2 write operations).
Note: in ServoBlaster and RPIO, it will consume exactly 16 DMA control blocks, because (for higher precision), they always perform a "memory copy" operation before a "wait operation". The "memory copy" operation is just a dummy unless it needs to change the pin value.
I need to create a virtual uart port on a stm32 microcontroller. The pins are given and can be changed to timer input channels. The recieving signal is going to be modulated in current and voltage and i need to detect both. Those two pins can not be assigned to a uart. Does somebody has a tutorial or something, that can lead me in the right direction? I just started programming microcontrollers and i am still strugeling with all the timer, interrupts and details stuff.
If we are talking aobut baudrates for small (9600), then you can achieve this with timer and EXTI.
On EXTI set pin to rising and falling edge and between each IRQs check timer value.
If value is greater than start and stop condition time, you failed, else you have to check time spent for EXTi and calculate whether you received 10101010 or 11001100 or any other combination.
For TX mode, use timer for precise interrupts at bit slice for UART output data and create state machine for data output bit by bit.
Another option is to use SPI as virtual UART.
i'm experiencing something that bugs me for days, so i am working on the imx6sx cortex m4 side, i have a sensor connected to one of the i2c buses, sensor is set up with data ready on INT1 which is connected to one of the gpios from the MCU. After boot, i configure the sensor so that it outputs data ready interrupt. Note that the i2c works also in interrupt mode, so if i try to read the sensor when the data ready line is asserted i have to wait in the GPIO INT Handler until the i2c transfer is complete in order to get another data ready int and so on.
My problem is that i don't want to wait in the GPIO INT Handler until the i2c transfer is complete, that's why i made the i2c on interrupts too, but if i don't wait in the GPIO Int Handler, something happens to the i2c because the sensor it's not ack the transfer, so i'n not getting other data-ready interrupts.
Please help if you have any idea what could be wrong, also the i2c bus Interrupt has a higher priority than the GPIO interrupt, and unfortunately i can't use a debugger for debugging, only the old-fashioned way, printfs in the console
Thanks
You could use INT1 to trigger a lower priority software interrupt to handle the i2c, then exit freeing the interrupt.
Consider using a RTOS to manage this for you.