voidinit(void){ // Set up an interrupt handler for DMA0 mcf5282_interrupt_init(9, MCF5282_INTC_ICR_IL(5) | MCF5282_INTC_ICR_IP(3), data_pump_isr); // Clear DMA0 MCF5282_DMA0_DSR = MCF5282_DMA_DSR_DONE; }/**************************************************************************** * FUNCTION: start_copy_isr(void) * * ISR servicing an external interrupt which starts the DMA data pump * * RETURNS: nothing * * When the interrupt is asserted, the peripheral has one or more buffers full of * data. This ISR will start a DMA transfer for the first full buffer. The * DMA completion interrupt will start another DMA transfer if there is any * more data left to transfer. * */__attribute__((interrupt_handler)) voidstart_copy_isr(){ // Some code removed here that just works out which // buffer to use as a destination - we have a double // buffering scheme in use here. SRC_BUFFER_BA(chnl) is // the address of the correct source buffer. // DST_BUFFER_BA(chnl) is the base address of the destination. // BUF_LEN is the buffer length. We make sure our // buffers are on 16-byte aligned addresses so that // we can fource line xfers. // Configure a DMA transfer to current_buffer MCF5282_DMA0_SAR = (uint32)SRC_BUFFER_BA(chnl); MCF5282_DMA0_DAR = (uint32)DST_BUFFER_BA(chnl); MCF5282_DMA0_BCR = BUF_LEN << 16; MCF5282_DMA0_DCR = 0 | MCF5282_DMA_DCR_INT // Enable DMA interrupt | MCF5282_DMA_DCR_SINC // Inc src addr | MCF5282_DMA_DCR_DINC // Inc dst addr | MCF5282_DMA_DCR_SSIZE_LINE // 16 byte src xfer | MCF5282_DMA_DCR_DSIZE_LINE; // 16 byte dst xfer MCF5282_DMA0_DCR |= MCF5282_DMA_DCR_START; // Start DMA xfer // A bit more housekeeping deleted here. Mainly to mask the // external peripheral's interrupt. The DMA completion ISR will // check if the peripheral still has more data to transfer.}/**************************************************************************** * FUNCTION: data_pump_isr(void) * * ISR for the data pump interrupt on DMA completion * * RETURNS: nothing * * When a DMA transfer completes, this handler will be called. The source peripheral * status is examined and if another buffer is ready to go, then another * DMA transfer is initiated. If there is no more data, we reset our * state to wait for another buffer full of data. * */__attribute__((interrupt_handler)) voiddata_pump_isr(void){ // Write DMA0(DONE) = 1 to clear interrupt MCF5282_DMA0_DSR = MCF5282_DMA_DSR_DONE; // The DMA transfer for the current buffer has completed. // Code removed here that will deal with the now filled // target buffer. // Check if any other buffers need to be serviced if (SRC_BUF_FULL(chnl)) { // Configure a DMA transfer to the relevant buffer MCF5282_DMA0_SAR = (uint32)SRC_BUFFER_BA(chnl); MCF5282_DMA0_DAR = (uint32)TGT_BUFFER_BA(chnl); MCF5282_DMA0_BCR = BUF_LEN << 16; MCF5282_DMA0_DCR = 0 | MCF5282_DMA_DCR_INT | MCF5282_DMA_DCR_SINC | MCF5282_DMA_DCR_DINC | MCF5282_DMA_DCR_SSIZE_LINE | MCF5282_DMA_DCR_DSIZE_LINE | MCF5282_DMA_DCR_START; // New DMA transfer is now started } else { // No more data so put the peripheral in a state so that it // can trigger a new transfer }}/* FUNCTION: mcf5282_interrupt_init() * * Initialise an interrupt handler for an interrupt source * for INTC0. If the handler is a NULL pointer, then mask * this interrupt. * * PARAM1: Interrupt source (1..62) * * PARAM2: Interrupt level and priority * * PARAM3: Interrupt handler * * RETURNS: none */voidmcf5282_interrupt_init(uint8 source, uint8 ipl, void (*handler)(void)){ // Only for user defined vectors in INTC0 if ((source > 0) && (source < 63)) { // Interrupts should be disabled to avoid vector problems // and to ensure that a spurious interrupt exception can't // be generated. uint8 sysint = asm_set_ipl(7); if (handler) { // Set interrupt priority level MCF5282_INTC0_ICR(source) = (ipl & 0x3F); // Set vector mcf5xxx_set_handler(source+64, (ADDRESS)handler); // Clear mask for this handler if (source < 32) MCF5282_INTC0_IMRL &= ~(MCF5282_INTC_IMRL_INT(source) | MCF5282_INTC_IMRL_MASKALL); else { MCF5282_INTC0_IMRL &= ~(MCF5282_INTC_IMRL_MASKALL); MCF5282_INTC0_IMRH &= ~(MCF5282_INTC_IMRH_INT(source)); } } else { // Set vector mcf5xxx_set_handler(source+64, (ADDRESS)handler); // Set mask for this handler if (source < 32) { MCF5282_INTC0_IMRL |= MCF5282_INTC_IMRL_INT(source); } else { MCF5282_INTC0_IMRH |= MCF5282_INTC_IMRH_INT(source); } } // As you were... asm_set_ipl(sysint); }}
OK, Paul. In the following lines you'll see the init procedure for the bridge (bridge_init), the init procedure for DMA (dma_uart_init), the Interrupt Enable procedure (EnableDMAinInterrupt) and the interrupt routine.
char bridge_init(unsigned char ucBridge, unsigned long int ulBaud_rateUART0, unsigned long int ulBaud_rateUART1){
struct uartbridge_desc* uartbridge;
// initialize structure
[...]
// initialize buffers
[...]
// initialize pointers
[...]
// initialize UART0
uartbridge->ucDevice_UART0=0;
if (uart_init(uartbridge->ucDevice_UART0, ulBaud_rateUART0) != -1){
uartbridge->ulSpeed_UART0=ulBaud_rateUART0;
uartbridge->vucUART0_idle=1;
uartbridge->ucInitdone_UART0=1;
printf("UART0 initialized\n\r");
}
// initialize UART1
uartbridge->ucDevice_UART1=1;
if (uart_init(uartbridge->ucDevice_UART1, ulBaud_rateUART1) != -1){
uartbridge->ulSpeed_UART1=ulBaud_rateUART1;
uartbridge->ucInitdone_UART1=1;
printf("UART1 initialized\n\r");
}
// UART1 DMA1
uartbridge->ucUART1_DMA_in=1; // initialize input DMA ch1
dma_uart_init(uartbridge->ucDevice_UART1, uartbridge->ucUART1_DMA_in, uartbridge->ucpUART1_RXBuf);
EnableDMAinInterrupt(ucBridge,UART1_DMA_ch); // unmask DMA1 interrupt
MCF_UART_UCR(uartbridge->ucDevice_UART1)=MCF_UART_UCR_RESET_MR; // reset UMR
MCF_UART_UMR(uartbridge->ucDevice_UART1) = ( MCF_UART_UMR_PM_NONE // no parity
| MCF_UART_UMR_SB(0x07) // stop bit
| MCF_UART_UMR_CM_NORMAL // no loopback
| MCF_UART_UMR_BC(0x03)); // 8 bit
// UART0 DMA0
uartbridge->uc_UART0_in=0; // initialize input DMA ch0
dma_uart_init(uartbridge->ucDevice_UART0, uartbridge->ucUART0_DMA_in, uartbridge->ucpUART0_RXBuf);
EnableDMAinInterrupt(ucBridge, UART0_DMA_ch); // unmask DMA0 interrupt
MCF_UART_UCR(uartbridge->ucDevice_UART0)=MCF_UART_UCR_RESET_MR; // reset UMR
MCF_UART_UMR(uartbridge->ucDevice_UART0) = ( MCF_UART_UMR_PM_NONE // no parity
| MCF_UART_UMR_SB(0x07) // stop bit
| MCF_UART_UMR_CM_NORMAL // no loopback
| MCF_UART_UMR_BC(0x03)); // 8 bit
return 0;
}
char dma_uart_init(unsigned char ucDev, unsigned char ucChan, unsigned char* ucpBuffer){
// route DMA channel 1 to UART1 module
if ((ucDev==1) && (ucChan==1)){
MCF_DMA_DMAREQC |= MCF_DMA_DMAREQC_DMAC1(0x9); //route DMA Ch1 to UART1 RX
MCF_DMA_SAR1=(volatile unsigned long)&MCF_UART1_URB; //DMA Ch1 source address
MCF_DMA_DAR1=(volatile unsigned long) ucpBuffer; //DMA Ch1 dest address
MCF_DMA_BCR1=MCF_DMA_BCR_BCR(BLOCKSIZE); //byte number
MCF_DMA_DCR1 |= MCF_DMA_DCR_INT | //enable int
MCF_DMA_DCR_EEXT | //enable external request
MCF_DMA_DCR_CS | //forces a single r/w cycle per request
MCF_DMA_DCR_SSIZE(0x1) | //1 byte size for source bus cycle
MCF_DMA_DCR_DINC | //enable dest increment
MCF_DMA_DCR_DSIZE(0x1); //1 byte size for dest bus cycle
MCF_SCM_RAMBAR |= MCF_SCM_RAMBAR_BDE; //enable access to SRAM
MCF_SCM_PACR2 |= MCF_SCM_PACR_UART1_RW; //give r/w access to user/superuser
printf("DMA1 initialized \n\r");
return 0;
}
// route DMA channel 0 to UART0 module
if ((ucDev==0) && (ucChan==0)){
MCF_DMA_DMAREQC |= MCF_DMA_DMAREQC_DMAC0(0x8); //route DMA Ch0 to UART0 RX
MCF_DMA_SAR0=(volatile unsigned long)&MCF_UART0_URB; //DMA Ch0 source address
MCF_DMA_DAR0=(volatile unsigned long) ucpBuffer; //DMA Ch0 dest address
MCF_DMA_BCR0=MCF_DMA_BCR_BCR(BLOCKSIZE); //byte number
MCF_DMA_DCR0 |= MCF_DMA_DCR_INT | //enable int
MCF_DMA_DCR_EEXT | //enable external request
MCF_DMA_DCR_CS | //forces a single r/w cycle per request
MCF_DMA_DCR_SSIZE(0x1) | //1 byte size for source bus cycle
MCF_DMA_DCR_DINC | //enable dest increment
MCF_DMA_DCR_DSIZE(0x1); //1 byte size for dest bus cycle
MCF_SCM_RAMBAR |= MCF_SCM_RAMBAR_BDE; //enable access to SRAM
MCF_SCM_PACR2 |= ((MCF_SCM_PACR_UART0_RW)<<4); //give r/w access to user/superuser
printf("DMA0 initialized \n\r");
return 0;
}
return -1;
}
void EnableDMAinInterrupt(unsigned char ucBridge, unsigned char ucDMA_number){
struct uartbridge_desc* uartbridge=&uartbridges[ucBridge];
if (ucDMA_number==1){ //DMA1 for UART1
MCF_INTC0_ICR10= DMA1_Int_setting;
MCF_INTC0_IMRL &= ~(MCF_INTC_IMRL_MASK10 | MCF_INTC_IMRL_MASKALL);
}
else if (ucDMA_number==0){ //DMA0 for UART0
MCF_INTC0_ICR9= DMA0_Int_setting;
MCF_INTC0_IMRL &= ~(MCF_INTC_IMRL_MASK9 | MCF_INTC_IMRL_MASKALL);
}
else {
printf("Enable DMA in int operation failed!");
}
}
The interrupt routine for DMA1 is:
__declspec(interrupt) void dma1_isr (void){
unsigned char ucUART_usr,ucDMA_usr,ucUART1Buf_next;
signed char scRoom;
struct uartbridge_desc* uartbridge;
unsigned char ucDevin;
unsigned char ucDMA_in;
int i;
ulUART1_Int_DMAin_hit++;
ucDevin=1;
ucDMA_in=1;
ucUART_usr=MCF_UART_USR(ucDevin); //read input UART status
MCF_UART_UCR(ucDevin)=MCF_UART_UCR_RESET_ERROR; //reset input UART error status
ucDMA_usr=MCF_DMA_DSR(ucDMA_in); //read DMA status
if (ucDMA_usr & MCF_DMA_DSR_DONE){ //check the interrupt source
ulUART1_Int_DMAin_done_hit++;
// input UART error check
if (ucUART_usr & (MCF_UART_USR_OE | //overrun error
MCF_UART_USR_PE | //parity error
MCF_UART_USR_FE | //framing error
MCF_UART_USR_RB )) //received break
{
printf("Input UART1 error.");
ulUART1_in_err_counter++;
}
// input DMA error check
if (ucDMA_usr & (MCF_DMA_DSR_CE | //configuration error
MCF_DMA_DSR_BES | //source error
MCF_DMA_DSR_BED | //dest error
MCF_DMA_DSR_REQ //pending req
)){
printf("Input DMA1 error.");
ulUART1_DMAin_err_counter++;
MCF_DMA_DSR(ucDMA_in) |= MCF_DMA_DSR_DONE;
MCF_DMA_DMAREQC=0; //remove routing between UART and DMA
}
else {
if ((ucUART1Buf_next=uartbridge->vucUART1Buf_in+BLOCKSIZE)>=UARTRTXBUFSIZE)
ucUART1Buf_next-=UARTRTXBUFSIZE;
// RX buf full check
scRoom=(uartbridge->vucUART1Buf_out - ucUART1Buf_next); //room left
if (scRoom < 0) scRoom+=UARTRTXBUFSIZE;
if (scRoom < BLOCKSIZE) ulUART1_DMAbytein_drop++; //no room left: drop one frame, don't update
else {
uartbridge->vucUART1Buf_in=ucUART1Buf_next; //there is room left: update vucRx_in
uartbridge->vucUART1_idle=0;
}
MCF_DMA_DAR(ucDMA_in)=(volatile unsigned long) (uartbridge->ucpUART1_RXBuf + uartbridge->vucUART1Buf_in); //update the DMA pointer
MCF_DMA_DMAREQC=0; //stop routing DMA channel to UART
MCF_DMA_DSR(ucDMA_in) |= MCF_DMA_DSR_DONE; //clear DMA interrupt and error bits
MCF_DMA_BCR(ucDMA_in) |= MCF_DMA_BCR_BCR(BLOCKSIZE);
MCF_DMA_DMAREQC |= MCF_DMA_DMAREQC_DMAC1(0x9); //restore routing DMA channel to UART
}
}
else ulUART1_Int_DMAin_diff_hit++;
}
The routine for DMA0 is dual. In the file mcf52235_vectors.s I modified the following:
//vector49: .long _irq_handler
vector49: .long _dma0_isr /* DMA0 ISR */
//vector4A: .long _irq_handler
vector4A: .long _dma1_isr /* DMA1 ISR */
vector4B: .long _irq_handler
Please, try to give me some hint.
Thank you in advance.
Kremer wrote:I just didn´t understand why you did this:MCF5282_DMA0_BCR = BUF_LEN << 16;
MCF5223x_DMA0_BCR = BUF_LEN;