| MCF52233_DMA&UART | |
呵呵,学习ColdFire。最近一直在弄一个52233的板子,现在跟大家分享下一些经历。 Coldfire有三个独立的全双工串口,对串口的操作跟其他的芯片也基本一样的。呵呵,不同的是Coldfire的串口可以通过DMA方式进行数据发送和接收。 首先是对串口的初始化,主要是完成数据位、停止位、检验位、波特率的设置另外就是选择串口使用的时钟信号来源(可以用内部总线时钟也可以用外部时钟引脚输入信号作为时钟),最后再使能发送接收位,串口就可以正常工作了。当使用DMA时要把串口的中断给关了,此时用中断标志位去触发DMA工作,另外需要注意的就是要设置PACR(Peripheral Access Control Register)跟GPACR0(Grouped peripheral access control register)使串口的那几个数据可以被DMA访问。 Coldfire有4路DMA。对于DMA的初始化很简单,以用DMA为串口0接收服务为例,有几个比较重要的地方: 1、通过DMAREQC设置一个DMA为UART0的receive服务; 2、设置source address 和 detinition address,其中SAR设置为UART0的URB地址,DAR设为接收数据的起始地址,在这里用一个数组来装接收到的数据,就把这个数组的首地址给DAR了,这个地址是在RAM里的; 3、BCR(Byte Counter Register)这是一次完整DMA需要传送的数据Byte数,每次成功传送数据后BCR里的值都会相应地减1、2或4当减到0时产生一个DONE中断,可在中断中对BCR及DAR进行重新设置,需要注意的是在重新设置前要先把DMA触发使能位EEXT进行清零,不然的话会出现配置错误的,再清所有标志位,最后才能重新设置需要修改的寄存器而不出错。 4、因为串口每次只有一个Byte的数据,所以SSIZE和DSIZE都设为Byte而且每传一次数据后SAR不改变,DAR加1。 5、最后再中断使能、开中断,就可以使DMA每接收完一定数据后产生一次中断,跟据需要进行相应的处理了。 代码如下: void uart0_init(uint16 baudrate) { uint32 div,SYS_CLOCK; SYS_CLOCK=60000000; MCF_GPIO_PUAPAR=MCF_GPIO_PUAPAR_UTXD0_UTXD0 //Reset Transmitter Receiver Mode Register MCF_UART0_UCR|=(0 |MCF_UART_UCR_RESET_TX |MCF_UART_UCR_RESET_RX |MCF_UART_UCR_RESET_MR); //No parity,8bit data MCF_UART0_UMR1=(0 |MCF_UART_UMR_PM_NONE |MCF_UART_UMR_BC_8); //1bit stop MCF_UART0_UMR2=(0 |MCF_UART_UMR_CM_NORMAL |MCF_UART_UMR_SB_STOP_BITS_1); //Set Rx and Tx buad by SYSTERM CLOCK MCF_UART0_UCSR=(0 |MCF_UART_UCSR_RCS_SYS_CLK |MCF_UART_UCSR_TCS_SYS_CLK); //Mask all UART interrupts MCF_UART0_UIMR=0; //set buad rate div=(SYS_CLOCK/32/baudrate); MCF_UART0_UBG1=(unsigned char)(div>>8); MCF_UART0_UBG2=(unsigned char)(div&0x00ff); //Enable Tx/Rx MCF_UART0_UCR=(0 |MCF_UART_UCR_TX_ENABLED |MCF_UART_UCR_RX_ENABLED); } void DMA_init(void) { char *decadd=receive; MCF_SCM_DMAREQC=MCF_SCM_DMAREQC_DMAC0(0x8);//UART0 receive //source address register MCF_DMA0_SAR= 0x4000020C; //destination address register MCF_DMA_DAR(0)=(uint32)decadd; //byte count MCF_DMA0_BCR=30; MCF_DMA0_DCR=MCF_DMA_DCR_INT //interrupt enable |MCF_DMA_DCR_EEXT //enable external request |MCF_DMA_DCR_CS //force a single read/write transfer per request |MCF_DMA_DCR_SSIZE(MCF_DMA_DCR_SSIZE_BYTE) |MCF_DMA_DCR_DINC |MCF_DMA_DCR_DSIZE(MCF_DMA_DCR_DSIZE_BYTE); //UART0 read MCF_SCM_PACR2=MCF_SCM_PACR_ACCESS_CTRL1(5); //read/write MCF_SCM_GPACR0=MCF_SCM_GPACR_ACCESS_CTRL(6); //interrupt enable MCF_INTC0_IMRL&=~MCF_INTC_IMRL_MASKALL; MCF_INTC0_IMRL&=~MCF_INTC_IMRL_INT_MASK9; //channel 0 MCF_INTC0_ICR09=MCF_INTC_ICR_IP(3)+MCF_INTC_ICR_IL(2); } void uart0_putchar(char c) { //Wait until space is available in the FIFO while (!(MCF_UART0_USR&MCF_UART_USR_TXRDY)) { ; } //Send the character MCF_UART0_UTB = (unsigned char)c; } unsigned char uart0_getchar() { //Wait until character has been received while (!(MCF_UART0_USR & MCF_UART_USR_RXRDY)) { }; return MCF_UART0_URB; } void uart0_putstr(char *str) { while(*str!=0) { uart0_putchar(*str++); } }
__declspec(interrupt:0) void DMA0_handler(void)//source 9 { uint8 int_status = MCF_DMA0_DSR; if(int_status & MCF_DMA_DSR_DONE) { if(int_status & MCF_DMA_DSR_CE) { uart0_putstr("configuration error\n"); } else if(int_status & MCF_DMA_DSR_BED) { uart0_putstr("destination bus error\n"); } else if(int_status & MCF_DMA_DSR_BES) { uart0_putstr("source bus error\n"); } else { uart0_putstr("dma0 transfer done\n"); uart0_putstr(receive); } //clear DMA0 interrupt MCF_DMA0_DCR&=~MCF_DMA_DCR_EEXT; MCF_DMA0_DSR |= MCF_DMA_DSR_DONE; MCF_DMA_DAR(0)=(uint32)receive; MCF_DMA0_BCR=30; MCF_DMA0_DCR|=MCF_DMA_DCR_EEXT; } if(int_status & MCF_DMA_DSR_BSY) { uart0_putstr("busy\n"); } if(int_status & MCF_DMA_DSR_REQ) { uart0_putstr("transfer remaining but channel not selected\n");} } |