Hallo zusammen,
ich möchte für ein Projekt einen SAMC21 mikrocontroller als SPI Slave
verwenden. Um die Daten schnell genug, und ohne den Prozessor dabei zu
stark auszulasten, möchte ich die Daten per DMA an das SPI Modul geben.
Meine Setup Funktion sieht aus wie folgt:
1 | static DmacDescriptor dma_descriptor_array[2] __attribute__ ((aligned (16)));
|
2 | static DmacDescriptor dma_writeback_array[2] __attribute__ ((aligned (16)));
|
3 |
|
4 | uint8_t dma_rx_buffer[8];
|
5 |
|
6 | void hal_init_dma(void) {
|
7 |
|
8 | MCLK->AHBMASK.bit.DMAC_ = 1;
|
9 |
|
10 | /* perform a software reset before enable DMA controller */
|
11 | DMAC->CTRL.reg &= ~DMAC_CTRL_DMAENABLE;
|
12 | DMAC->CTRL.reg = DMAC_CTRL_SWRST;
|
13 |
|
14 | /* setup descriptopr base address and write back section base address */
|
15 | DMAC->BASEADDR.reg = (uint32_t) &dma_descriptor_array;
|
16 | DMAC->WRBADDR.reg = (uint32_t) &dma_writeback_array;
|
17 |
|
18 | /* enable all priority level at the same time */
|
19 | DMAC->CTRL.reg = DMAC_CTRL_DMAENABLE | DMAC_CTRL_LVLEN(0xf);
|
20 |
|
21 | /* perform a reset for channel 0 */
|
22 | DMAC->CHID.reg = DMAC_CHID_ID(0);
|
23 | DMAC->CHCTRLA.reg &= ~DMAC_CHCTRLA_ENABLE;
|
24 | DMAC->CHCTRLA.reg = DMAC_CHCTRLA_SWRST;
|
25 |
|
26 | DMAC->CHCTRLB.reg = DMAC_CHCTRLB_TRIGACT_BEAT;
|
27 | DMAC->CTRL.reg = DMAC_CTRL_LVLEN0 | DMAC_CTRL_DMAENABLE;
|
28 |
|
29 | dma_descriptor_array[0].BTCTRL.reg = DMAC_BTCTRL_DSTINC| DMAC_BTCTRL_VALID;
|
30 | dma_descriptor_array[0].BTCNT.reg = 8;
|
31 | dma_descriptor_array[0].SRCADDR.reg = (uint32_t) &SERCOM5->SPI.DATA;
|
32 | dma_descriptor_array[0].DSTADDR.reg = (uint32_t) &dma_rx_buffer[8];
|
33 | dma_descriptor_array[0].DESCADDR.reg = 0;
|
34 |
|
35 | DMAC->PRICTRL0.reg = 0;
|
36 | }
|
Ich würde gerne 8 Byte Daten nach dem Empfangen direkt in den
dma_rx_buffer schreiben.
Mein aktueller Ansatz wäre es bei einem Chip Select Low Interrupt per
software-flag einen DMA Transfer zu starten.
Ich habe das SERCOM5 Modul als SPI Slave konfiguriert. Das funktioniert
auch, konnte ich bereits ohne DMA testen.
1 | void SERCOM5_Handler() {
|
2 |
|
3 | /* flag is set when nCS pin is going low */
|
4 | if (SERCOM5->SPI.INTFLAG.bit.SSL && SERCOM5->SPI.INTENSET.bit.SSL) {
|
5 | SERCOM5->SPI.INTFLAG.reg = SERCOM_SPI_INTFLAG_SSL;
|
6 | DMAC->CHID.reg = DMAC_CHID_ID(0);
|
7 | DMAC->CHCTRLA.reg |= DMAC_CHCTRLA_ENABLE;
|
8 | }
|
9 | }
|
Leider scheint mein Ansatz so nicht zu funktionieren. Kann mir jemand
mit dem Problem weiterhelfen und ist das überhaupt der richtige Ansatz
für den Empfang der Daten mit DMA? Habe ich vielleicht einen Fehler in
der Konfig des DMA Controllers? Danke für eure Hilfe.