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;
}
}
*/