ref: 385ecf9c11ba7114801e877090951e1785698051
dir: /dma.c/
#include <u.h> #include "dat.h" #include "fns.h" #include "include/stm32f103xb.h" #include "libkern/kern.h" #include "debug.h" #define ISR_TCIF(c) (1 << ((c << 2) + 1)) #define CHANBUF_NULL 0xF00 typedef struct Chanbuf { // TODO locking short buf[DMA_BUFSIZE]; uint index, ltc; } Chanbuf; static Chanbuf *dma_chbufs[6] = { nil }; void dma_ch6init(void); void dma_ch7init(void); /* DMA init & enable */ void dmainit() { dma_ch6init(); // dma_ch7init(); } void dmaen() { // enable appropriate channels DMA1_Channel6->CCR |= DMA_CCR_EN; //! DMA1_Channel7->CCR |= DMA_CCR_EN; } /* DMA general purpose functions */ void dma_write(DmaChannel c, void *buf, ulong n) { DBGDMAWR print("dmawr%d: write: %uld bytes\n", c + 1, n); DMA_Channel_TypeDef *dma = nil; switch(c) { case DmaChan1: dma = DMA1_Channel1; break; case DmaChan2: dma = DMA1_Channel2; break; case DmaChan3: dma = DMA1_Channel3; break; case DmaChan4: dma = DMA1_Channel4; break; case DmaChan5: dma = DMA1_Channel5; break; case DmaChan6: dma = DMA1_Channel6; break; case DmaChan7: dma = DMA1_Channel7; break; default: panic("dma: cannot write to DMA channel %d\n", c + 1); return; } while(n) { DBGDMAWR print("dmawr%d: %uld bytes left\n", c + 1, n); while(dma->CCR & DMA_CCR_EN != 0 && (DMA1->ISR & ISR_TCIF(c)) == 0); dma->CCR &= ~DMA_CCR_EN; dma->CMAR = (uint)buf; dma->CNDTR = (uint)(n & 0xfff); dma->CCR |= DMA_CCR_EN; buf = (void*)((uint)buf + (uint)(n & 0xfff)); n = n >> 16; } DBGDMAWR print("dmawr%d: write call done\n", c + 1); } ulong dma_read(DmaChannel c, void *vbuf, ulong n) { DBGDMARD print("dmard%d: read: %uld bytes\n", c + 1, n); Chanbuf *chanbuf = dma_chbufs[c]; char *buf = vbuf; ulong m = 0; if(chanbuf == nil) panic("dma: channel %d has no chanbuf\n", c + 1); while(n) { DBGDMARD print("dmard%d: %uld bytes left\n", c + 1, n); for(; chanbuf->index < DMA_BUFSIZE && n > 0 && chanbuf->buf[chanbuf->index] != CHANBUF_NULL; chanbuf->index++) { *buf = (char)(chanbuf->buf[chanbuf->index] & 0xff); chanbuf->buf[chanbuf->index] = CHANBUF_NULL; n--; m++; buf++; } if(chanbuf->index == DMA_BUFSIZE) chanbuf->index = 0; if(chanbuf->buf[chanbuf->index] & CHANBUF_NULL) { DBGDMARD print("dmard%d: read call done; %uld / %uld\n", c + 1, m, n); return m; } } DBGDMARD print("dmard%d: read call done; buffer full\n", c + 1); return n; } /* DMA Channel 6 - USART2 RX */ void dma_ch6init() { DMA_Channel_TypeDef *dma = DMA1_Channel6; // dma configuration dma->CCR = DMA_CCR_CIRC | // circular mode DMA_CCR_MINC; // mem increment dma->CCR |= DMA_CCR_MSIZE_0; dma->CCR |= DMA_CCR_PL_0 | DMA_CCR_PL_1; // buffer init dma_chbufs[5] = malloc(sizeof(Chanbuf)); dma_chbufs[5]->index = 0; for(int i = 0; i < DMA_BUFSIZE; i++) dma_chbufs[5]->buf[i] = CHANBUF_NULL; // specific addresses dma->CPAR = (uint)&USART2->DR; dma->CMAR = (uint)dma_chbufs[5]->buf; dma->CNDTR = DMA_BUFSIZE; } /* DMA Channel 7 - USART2 TX */ void dma_ch7init() { DMA_Channel_TypeDef *dma = DMA1_Channel7; // dma configuration dma->CCR = DMA_CCR_DIR | // mem->periph DMA_CCR_MINC; // memory increment dma->CCR |= DMA_CCR_PL_0 | DMA_CCR_PL_1; // specific addresses dma->CPAR = (uint)&USART2->DR; dma->CNDTR = 0; } /* DMA interrupt handlers section */ /* void dma_ch7handler() { if(DMA1->ISR & DMA_ISR_TCIF7) { DMA1->IFCR |= DMA_IFCR_CGIF7; DMA1_Channel7->CCR &= ~DMA_CCR_EN; } } */