2024-04-10 04:00 AM - edited 2024-04-10 09:55 PM
Hi,
I am trying to get DMA to work with memory as source and peripheral as dest (UART) and i am not using HAL (this is a learning exercise), but only so far i have managed to get a single character out and the transmission reports as completed (Transfer complete status is set in ISR register and CNDTR from configured value becomes 0).
#define buff_size 6U
uint8_t source_buff[buff_size] = {'h', 'e', 'l', 'l', '0', '\n'};
void DMAInit(void) {
// Enable DMA1
RCC->AHBENR |= (1U << 0);
// Channel configuration
DMA1_Channel7->CCR &= ~(1U << 0); // disable
// wait for DMA to disable
while(DMA1_Channel7->CCR & (1U << 0));
// memory size set to 8 bits
DMA1_Channel7->CCR &= ~(1U << 10);
DMA1_Channel7->CCR &= ~(1U << 11);
// peripheral size set to 8 bits
DMA1_Channel7->CCR &= ~(1U << 8);
DMA1_Channel7->CCR &= ~(1U << 9);
// read from memory to peripheral, DIR = 1
DMA1_Channel7->CCR |= (1U << 4);
// mem inc
DMA1_Channel7->CCR |= (1U << 7);
// peipheral constant addr
DMA1_Channel7->CCR &= ~(1U << 6);
// CIRC circular buffer disable
DMA1_Channel7->CCR &= ~(1U << 5);
// MEM2MEM enable
DMA1_Channel7->CCR |= (1U << 14);
// dest address
DMA1_Channel7->CPAR = (uint32_t)&USART2->TDR;
// source buffer
DMA1_Channel7->CMAR = (uint32_t)source_buff;
// enable priority, very high
DMA1_Channel7->CCR |= (1U << 13);
DMA1_Channel7->CCR |= (1U << 12);
// size of transfer
DMA1_Channel7->CNDTR = buff_size; //buff_size;
// reset global interrupt flag.
DMA1->IFCR |= (1U << 24);
return;
}
here is how i am triggering the DMA request
void startTransfer(void) {
// clear TC flag by setting TCCF bit in UART CR
USART2->ICR |= UART2_ICR_TCCF;
// Enable DMA
DMA1_Channel7->CCR |= (1U << 0);
// Monitor TC for entire block transfer complete notification
while(!(USART2->ISR & UART2_ICR_TC));
return;
}
any help or pointers is appreciated.
Thanks.
Solved! Go to Solution.
2024-04-10 04:15 AM - edited 2024-04-10 04:18 AM
Contrary to the title, this *does* work as expected.
M2M DMA transfers data as quickly as possible, with no regard what the target does with that data. So here it simply dumps data to the UART's data register, and UART simlpy ignores every data written to that register while TXE status bit is not set (which is not set that quickly).
There is a reason why DMA transfers directed to peripherals should be triggered by that peripheral (here, the UART_Tx trigger) and should not be M2M.
JW
PS. Style: don't write registers (here DMAx_Channelx_CCR) piece-wise. Assemble the value you want to write there and perform one write. Also, for individual fields in registers (or for the shift amounts, if it's not a single-bit value) use the symbols defined in the device header.
PS2. When posting code here, please use the "</>" icon at top of the editor pane.
2024-04-10 04:15 AM - edited 2024-04-10 04:18 AM
Contrary to the title, this *does* work as expected.
M2M DMA transfers data as quickly as possible, with no regard what the target does with that data. So here it simply dumps data to the UART's data register, and UART simlpy ignores every data written to that register while TXE status bit is not set (which is not set that quickly).
There is a reason why DMA transfers directed to peripherals should be triggered by that peripheral (here, the UART_Tx trigger) and should not be M2M.
JW
PS. Style: don't write registers (here DMAx_Channelx_CCR) piece-wise. Assemble the value you want to write there and perform one write. Also, for individual fields in registers (or for the shift amounts, if it's not a single-bit value) use the symbols defined in the device header.
PS2. When posting code here, please use the "</>" icon at top of the editor pane.
2024-04-10 04:22 AM - edited 2024-04-10 04:23 AM
this diagram states that TXE flag is acknowledged by DMA and cleared after every read, so is this not the case on M2M ?
sorry if i am missing the obvious, this is my first micro-controller, and still am getting hang of things.
also if i remember properly, M2M is just a way of triggering DMA request right ?
Thanks.
2024-04-10 05:56 AM
First that text should say "Cleared by DMA *write* (as TDR is *written* by DMA, not read) ( @Imen.D , can you please have a look at this? It's RM0316. Btw. the next figure, Fig.345 has an error, too, in labeling the first line, it should be Rx rather than Tx. Thanks.)
Second M2M DMA mode does not work out the peripheral triggers (the more correct expression, used also on that figure is "requests"); it simply shovels data from source to destination as quickly as possible.
JW
2024-04-10 09:50 PM - edited 2024-04-10 09:53 PM
yes, disabling M2M seems to get the intended results, thanks !
> Second M2M DMA mode does not work out the peripheral triggers (the more correct expression, used also on that figure is "requests"); it simply shovels data from source to destination as quickly as possible.
just curious, where is this information specified ?
PS:
> PS. Style: don't write registers (here DMAx_Channelx_CCR) piece-wise. Assemble the value you want to write there and perform one write. Also, for individual fields in registers (or for the shift amounts, if it's not a single-bit value) use the symbols defined in the device header.
yes, that makes sense, will do.
> PS2. When posting code here, please use the "</>" icon at top of the editor pane.
got it !, i overlooked that symbol :)
2024-04-10 11:42 PM
It's kind of a "common knowledge" one is supposed to learn in college or so. Nonetheless, it's thankfully properly documented in the RM, too:
JW
2024-04-14 11:58 PM
Hi @waclawek.jan,
Thank you for highlighting this.
An internal ticket (number 178892) is submitted in order to fix the typos.
PS: Ticket number is only for reference, not available outside of ST.