-
Notifications
You must be signed in to change notification settings - Fork 133
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
STM32 UART/DMA Transfer Request Fixes #116
base: master
Are you sure you want to change the base?
Conversation
If the token is evaluated after the timer checks it then the cancellation token source has changed, and the new value is checked. This caused every timer to cause an idle line interrupt. Evaluating the token before starting the timer means that the cancellation status is not overwritten by new tokens.
This commit attempts to reproduce the behaviour descrbed in Figure 316. "Reception using DMA" of the STM32F4 Referance Manual (RM0090) We implement the IDMA interface in the DMA, and from the UART we request a DMA transfer when value enters data register. If there is a dma peripheral assigned, then when a value appears in the DR, request a transfer. When a transfer is requested by a peripheral a counter keeps track of how many have been requested. The counter is decremented each time a transfer happens. When the DMA is re-enabled, any transfers that were requested while it was disabled are processed. This is useful for multi-buffering UART, eg with the Zephyr asynchronous UART API.
There is also the problem in the DMA where the SxNDTR register is never decremented by a transfer. This means the Zephyr driver for async uart never triggers the UART_RX_RDY event when the IDLE interrupt happens. I have fixed it locally and will add to this PR The Reference manual for the STM32F4 Says:
But this post decrement is not currently in the DMA model. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @tomhepworth, thanks for your contribution!
It looks generally fine, there is just one question.
@@ -399,6 +429,8 @@ private static uint FromTransferType(TransferType transferType) | |||
} | |||
throw new InvalidOperationException("Should not reach here."); | |||
} | |||
|
|||
public uint transferBacklog; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering if having a counter here is correct.
DoPeripheralTransfer
uses transfer parameters set by HandleConfigurationWrite
. This means that once a channel is enabled, all the queued transfers will use the same configuration (which I believe can be different than the one when the transfer was "scheduled").
Is the counter logic necessary to pass your example?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a good point which I have not tested.
It is necessary in the case where the DMA runs out of space in a buffer while the uart is still receiving data. In its original state the DMA will miss some bytes. This happens because during the buffer swap procedure in the zephyr driver a UART interrupt register is reset which causes a read from the UART data register, dequeuing a value. Unless the amount of requested transfers is kept track of and processed when the DMA is re-enabled and before the UART is reconfigured, then some data is lost.
I am not 100% sure what the real DMA hardware does in this case, but in the figure I mention in the PR description it shows a request being generated which I assumed would be queued/buffered somehow.
I will investigate
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without the counter, wouldn't the dma just do the same thing but also lose the data that my implementation fixes?
If data is being streamed and the DMA is reconfigured halfway through, then the second half will have the new settings.
The main purpose of this PR is to address the missing features when trying to use the STM32 UART peripheral with the DMA in the STM32F4. The behaviour should now work more like Figure 316. "Reception using DMA" of the STM32F4 Referance Manual (RM0090).
Hopefully this PR will make it easier to set up and use the Zephyr async uart api on the STM32F4 boards, and enable easier testing of serial protocols with variable length packets.
We implement the IDMA interface in the DMA, and from the UART we request a DMA transfer when value enters data register. If there is a dma peripheral assigned, then when a value appears in the DR, request a transfer.
When a transfer is requested by a peripheral a counter keeps track of how many have been requested. The counter is decremented each time a transfer happens. When the DMA is re-enabled, any transfers that were requested while it was disabled are processed. This is useful for multi-buffering UART, eg with the Zephyr asynchronous UART API.
This includes a fix to the idleLineInterrupt detection in the uart, indended to address renode/renode#690
Below I have included the robot test, zephyr app, and resc file which I have used for testing. The robot test fails on master of
renode-infrastructure
, but passes on my PR. The zephyr app is an example of a simple serial protocol with variable length packets using the Zephyr Async UART API. The only implemented "opcode" is one to transmit back a packet which was received. Both TX and RX are using the DMA, so if the uart & dma are working, then the packet received should match the one sent.Changes to board description required to enable the DMA:
Example shown for USART2
Robot Test
Zephyr App
Kconfig
DTC overlay
platform.resc