dma_example.c - Uses DMA in ping-pong mode to capture data from the UART, write it to the 24LC515 EEPROM¶
#include "pic24_all.h"
#define EEPROM (0xA0) //LC515 address assuming both address pins tied low.
#define BLKSIZE (64)
//Assumes WDT is configured for longer than EEPROM write time
void waitForWriteCompletion(uint8_t u8_i2cAddr) {
uint8_t u8_ack, u8_savedSWDTEN;
u8_savedSWDTEN = _SWDTEN;
_SWDTEN = 1; //enable WDT so that do not get stuck in infinite loop!
u8_i2cAddr = I2C_WADDR(u8_i2cAddr); //write operation, R/W# = 0;
do {
startI2C1();
u8_ack = putNoAckCheckI2C1(u8_i2cAddr);
stopI2C1();
} while (u8_ack == I2C_NAK);
_SWDTEN = u8_savedSWDTEN; //restore WDT to original state
}
//this version just expects a block of 64 data bytes
void memWriteLC515(uint8_t u8_i2cAddr, uint16_t u16_MemAddr, uint8_t *pu8_buf) {
uint8_t u8_AddrLo, u8_AddrHi;
uint16_t u16_i;
u8_AddrLo = u16_MemAddr & 0x00FF;
u8_AddrHi = (u16_MemAddr >> 8);
if (u16_MemAddr & 0x8000) {
if MSB set , set block select bit
u8_i2cAddr = u8_i2cAddr | 0x08;
}
waitForWriteCompletion(u8_i2cAddr);
//write the data to the EEPROM
startI2C1();
putI2C1(I2C_WADDR(u8_i2cAddr));
putI2C1(u8_AddrHi);
putI2C1(u8_AddrLo);
for (u16_i=0; u16_i < BLKSIZE; u16_i++) {
putI2C1(*pu8_buf);
pu8_buf++;
}
stopI2C1();
}
void memReadLC515(uint8_t u8_i2cAddr, uint16_t u16_MemAddr, uint8_t *pu8_buf) {
uint8_t u8_AddrLo, u8_AddrHi;
u8_AddrLo = u16_MemAddr & 0x00FF;
u8_AddrHi = (u16_MemAddr >> 8);
if (u16_MemAddr & 0x8000) {
if MSB set , set block select bit
u8_i2cAddr = u8_i2cAddr | 0x08;
}
waitForWriteCompletion(u8_i2cAddr);
//set address counter
write2I2C1(u8_i2cAddr,u8_AddrHi, u8_AddrLo);
//read data
readNI2C1(u8_i2cAddr,pu8_buf, BLKSIZE);
}
#define DMA_TRANSFER_SIZE BLKSIZE
//define DMA buffers
#if defined(__PIC24H__) || defined (__dsPIC33F__)
uint8_t au8_bufferA[DMA_TRANSFER_SIZE] __attribute__((space(dma)));
uint8_t au8_bufferB[DMA_TRANSFER_SIZE] __attribute__((space(dma)));
#elif defined(__dsPIC33E__)
uint8_t au8_bufferA[DMA_TRANSFER_SIZE] __attribute__((space(xmemory),aligned(DMA_TRANSFER_SIZE)));
uint8_t au8_bufferB[DMA_TRANSFER_SIZE] __attribute__((space(xmemory),aligned(DMA_TRANSFER_SIZE)));
#else
#error "DMA memory not properly defined for this processor."
#endif
//some one-bit flags
typedef struct tagFLAGBITS {
unsigned u1_activeBuffer:
1;
unsigned u1_writeFlag:
1;
} FLAGBITS;
volatile FLAGBITS flags;
/***************************************************************************
****************************************************************************
2008 CODE for PIC24H
***************************************************************************
void configDMA0() {
DMA0PAD = (unsigned int) &U1RXREG; //peripheral address to read
DMA0REQ = DMA_IRQ_U1RX; //source from UART1 RX
_U1RXIF = 0; //clear the UART RX IF flag
//set up ping pong buffer registers
#if defined(__PIC24H__) || defined (__dsPIC33F__)
DMA0STA = __builtin_dmaoffset(au8_bufferA);
DMA0STB = __builtin_dmaoffset(au8_bufferB);
#elif defined(__PIC24E__)
DMA0STAH = __builtin_dmaoffset(au8_bufferA);
DMA0STAL = __builtin_dmaoffset(au8_bufferA);
DMA0STBH = __builtin_dmaoffset(au8_bufferB);
DMA0STBL = __builtin_dmaoffset(au8_bufferB);
#endif
//setup transfer size
DMA0CNT = DMA_TRANSFER_SIZE -1;
DMA0CON = //configure and enable the module Module
(DMA_MODULE_ON |
DMA_SIZE_BYTE |
DMA_DIR_READ_PERIPHERAL |
DMA_INTERRUPT_FULL |
DMA_NULLW_OFF |
DMA_AMODE_REGISTER_POSTINC |
DMA_MODE_CONTINUOUS_PING_PONG);
//enable the UART1RX Error interrupt
_U1EIF = 0;
_U1EIP = 1;
_U1EIE = 1;
//enable DMA channel 0 interrupt
_DMA0IF = 0;
_DMA0IP = 2;
_DMA0IE = 1;
}
***************************************************************************/
/***************************************************************************
** Configure DMA engine
**
** There are slight differences in the dsPIC33E/PIC24E devices from
** the previous devices (F,H, etc.)
**
***************************************************************************/
#if defined(__PIC24H__) || defined (__dsPIC33F__)
ECANMSG msgBuf[NUM_BUFS] __attribute__((space(dma),aligned(NUM_BUFS*16)));
//define DMA buffers
uint8_t au8_bufferA[DMA_TRANSFER_SIZE] __attribute__((space(dma)));
uint8_t au8_bufferB[DMA_TRANSFER_SIZE] __attribute__((space(dma)));
//configure DMA transmit buffer
void configDMA0(void) {
DMACS0 = 0;
_DMA0IF = 0; // clear DMA0 IF
_U1RXIF = 0; // clear the UART RX IF
DMA0PAD = (unsigned int) &U1RXREG; // read from UART peripheral RX register
DMA0REQ = DMA_IRQ_U1RX; // DMA requests will come from UART1 RX
address of two ping-pong buffers (target mem where DMA will xfer data to)
DMA0STA = __builtin_dmaoffset(au8_bufferA);
DMA0STB = __builtin_dmaoffset(au8_bufferB);
DMA0CNT = DMA_TRANSFER_SIZE -1; // number of byte/words to transfer each DMA request
configure and enable the DMA0 module DMA0 will “READ” “BYTES” giving interrupts when buffer is full, “POSTINCREMENT” the addresses to set thru buffer, and will “PING_PONG” next transfer into a second buffer
DMA0CON =
(DMA_MODULE_ON |
DMA_SIZE_BYTE |
DMA_DIR_READ_PERIPHERAL |
DMA_INTERRUPT_FULL |
DMA_NULLW_OFF |
DMA_AMODE_REGISTER_POSTINC |
DMA_MODE_CONTINUOUS_PING_PONG);
//enable the UART1RX Error interrupt
_U1EIF = 0;
_U1EIP = 1;
_U1EIE = 1;
//enable DMA channel 0 interrupt
_DMA0IF = 0;
_DMA0IP = 2;
_DMA0IE = 1;
}
#elif defined(__dsPIC33E__)
//ECANMSG msgBuf[NUM_BUFS] __attribute__((space(xmemory),aligned(NUM_BUFS*16)));
uint8_t au8_bufferA[DMA_TRANSFER_SIZE] __attribute__((space(xmemory),aligned(DMA_TRANSFER_SIZE)));
uint8_t au8_bufferB[DMA_TRANSFER_SIZE] __attribute__((space(xmemory),aligned(DMA_TRANSFER_SIZE)));
//configure DMA transmit buffer
void configDMA0(void) {
DMAPWC = 0; // Reset the DMA Peripheral Write Collision Status Register
_DMA0IF = 0; // clear DMA0 IF
_U1RXIF = 0; // clear the UART RX IF
DMA0PAD = (unsigned int) &U1RXREG; // read from UART peripheral RX register
DMA0REQ = DMA_IRQ_U1RX; // DMA requests will come from UART1 RX
address of two ping-pong buffers (target mem where DMA will xfer data to)
DMA0STAL = __builtin_dmaoffset(au8_bufferA);
DMA0STAH = 0;
DMA0STBL = __builtin_dmaoffset(au8_bufferB);
DMA0STBH = 0;
DMA0CNT = DMA_TRANSFER_SIZE -1; // number of byte/words to transfer each DMA request
configure and enable the DMA0 module DMA0 will “READ” “BYTES” giving interrupts when buffer is full, “POSTINCREMENT” the addresses to set thru buffer, and will “PING_PONG” next transfer into a second buffer
DMA0CON =
(DMA_MODULE_ON |
DMA_SIZE_BYTE |
DMA_DIR_READ_PERIPHERAL |
DMA_INTERRUPT_FULL |
DMA_NULLW_OFF |
DMA_AMODE_REGISTER_POSTINC |
DMA_MODE_CONTINUOUS_PING_PONG);
//enable the UART1RX Error interrupt
_U1EIF = 0;
_U1EIP = 1;
_U1EIE = 1;
//enable DMA channel 0 interrupt
_DMA0IF = 0;
_DMA0IP = 2;
_DMA0IE = 1;
}
#else
#error "DMA has not been configured for this chip. Edit chap13/dma_example.c."
#endif
//UART error interrupt, need this with DMA since DMA does not check for errors.
void _ISRFAST _U1ErrInterrupt(void) {
_U1EIF = 0; //clear the UART1 Error flag
checkRxErrorUART1();
}
//interrupted when a ping-pong buffer is full
void _ISRFAST _DMA0Interrupt(void) {
_DMA0IF = 0;
flags.u1_activeBuffer = !flags.u1_activeBuffer;
flags.u1_writeFlag = 1;
}
int main (void) {
uint8_t au8_eepromBuf[BLKSIZE]; //holds read data from EEPROM
uint16_t u16_MemAddr;
uint8_t u8_mode, u8_pause;
configBasic(HELLO_MSG);
configI2C1(400); //configure I2C for 400 KHz
outString("\nEnter 'w' for write mode, anything else reads: ");
u8_mode = inCharEcho();
outString("\n");
u16_MemAddr = 0; //start at location 0 in memory
u8_pause = 0;
while (1) {
uint8_t u8_i;
if (u8_mode == 'w') {
configDMA0();
while (1) {
if (flags.u1_writeFlag) reportError("DMA overflow!\n");
while (!flags.u1_writeFlag) doHeartbeat();
flags.u1_writeFlag = 0;
if (flags.u1_activeBuffer)
memWriteLC515(EEPROM,u16_MemAddr,au8_bufferA);
else
memWriteLC515(EEPROM,u16_MemAddr,au8_bufferB);
u16_MemAddr = u16_MemAddr +64;
outString("*");
}//end while(1), press reset to escape
} else {
while (1) {
if (u8_pause) {
inChar(); //get a character
u8_pause = 0;
}
memReadLC515(EEPROM,u16_MemAddr,au8_eepromBuf); // do read
for (u8_i = 0; u8_i< 64; u8_i++) outChar(au8_eepromBuf[u8_i]);
if (isCharReady()) {
inChar();
u8_pause = 1;
}
u16_MemAddr = u16_MemAddr + 64;
}//end while(1) read mode, press reset to escape
}//end else
}//end while(1) main
}//end main