- 论坛徽章:
- 0
|
本帖最后由 云碁 于 2015-05-19 12:34 编辑
之前接收动态数据帧一直用超时法,这个缺点是每个串口单独占用一个定时器。后来看见串口CR1寄存器中有个空闲帧位,偶然听Ted白用着并调试成功,故着手自己也弄个-----因为都知道DMA速度快,少占用CPU么(其实DMA传送数据是占CPU数据总线至多一半带宽的,压力测试的时候更是能体现出来。压力极限测试我感觉用不用DMA此时都一样)。
开始写之前,说几件事。
串口我开辟了内存池(vu8 USART1_RX_BUF[USART1_BUF_LEN];),ZET6总共才64K RAM ,也就是1024*64 = 65535. DMA_CNDTR这个寄存器是32bit的,但用了低16位。
故一次DMA传输怎么也得 小于65535,其实1024*20K就已经很了不得了。我做网关不带GUI的时候最多开到1024*40。
还有个原因:
CNDTR 一旦在开启DMA后是只读的,每次用DMA传送,CNDTR--。当减到0的时候,这时候若是没有开启循环,DMA就会终止传送数据;开启循环的时候,CNDTR会Reload原来的初始值。 最让人头疼的是CxAR(假若设置了自动增量)会跑到起始地址。咋的一看是很方便的,但对于传输大于64K的数据,比如Bootloader就比较坑了,每次64K传完,就又回到BootLoader首地址了。
至今没找到内存中大于64K的数据传送的好办法。- #define DMA_CNDTR_RELOAD 65535 /*DMA 传送缓冲大小*/
- ==================================================================
- [code]#define EN_USART1 1u /*使能串口x(1.2.3.4.5)*/
- #define EN_USART2 0u
- #define EN_USART3 0u
- #define EN_UART4 0u
- #define EN_UART5 0u
- #define EN_USART1_DMA 1u
- #define DMA_USART1_TX 1u
- #define DMA_USART1_RX 1u
- #define USART1_BUF_LEN 10240u /*串口x(1.2.3.4.5)缓冲大小*/
- #define USART2_BUF_LEN 256u
- #define USART3_BUF_LEN 256u
- #define UART4_BUF_LEN 256u
- #define UART5_BUF_LEN 256u
- #pragma pack(1)
- typedef struct{
- #if EN_USART1
- vu8 USART1_RX_BUF[USART1_BUF_LEN];
- vu8 USART1_TX_BUF[USART1_BUF_LEN];
- volatile unsigned short USART1_STA;
- volatile unsigned int USART1_RxCnt;
- volatile unsigned int USART1_TxCnt;
- #endif
-
- }_UART_BUF_;
复制代码 ===================================================================
================================================================- #define DMA_CNDTR_RELOAD 65535 /*DMA 传送缓冲大小*/
- /*************************************************
- Function: void Usart1_Init(u16 psc,u32 BaudRate)
- Description: 串口1初始化,此串口默认还兼顾Printf函数
- Called By:
- Others:
- *************************************************/
- void Usart1_Init(u16 psc,u32 BaudRate)
- {
- float temp;
- u16 DIV_Mantissa,DIV_Fraction;
- temp = (float)(psc*1000000)/(16 * BaudRate);
- DIV_Mantissa = temp;
- DIV_Fraction = (temp - DIV_Mantissa)*16;
- DIV_Mantissa = (DIV_Mantissa<<4) + DIV_Fraction;
- RCC->APB2ENR |= (1<<2) | (1<<14); //使能A、USART1时钟
- GPIOA->CRH &= 0xfffff00f;
- GPIOA->CRH |= 0x000008b0;
-
- RCC->APB2RSTR |= 1<<14;
- RCC->APB2RSTR &= ~(1<<14);
- USART1->BRR = DIV_Mantissa;
-
-
- USART1->CR1 |= (1<<13) | 0x0c; /*USART1模块使能,发送和接收使能*/
-
- #if EN_USART1
- USART1->CR1 |= 1<<4; /*空闲中断使能*/
- MY_NVIC_Init(3,1,USART1_IRQChannel,2);
-
- RCC->AHBENR |= (1<<0);//DMA1 ENR
- _delay_ms(5);
- /*通道4是用作USART1的发送*/
- #if DMA_USART1_TX
- USART1->CR3 |= (1<<7) ; /*DMA发送*/
- DMA1_Channel4->CNDTR = 0;
- DMA1_Channel4->CPAR = (u32)&(USART1->DR);
- DMA1_Channel4->CMAR = (u32)UART_BUF.USART1_RX_BUF;
- DMA1_Channel4->CCR = 0;
- DMA1_Channel4->CCR = (1<<13)|(1<<7) | (1<<4) ; /*中优先级 存储器地址增量 从存储器读 */
- DMA1_Channel4->CCR |= (1<<1); /*传输完成中断*/
- MY_NVIC_Init(0,1,DMA1_Channel4_IRQChannel,2);
- #endif
- #if DMA_USART1_RX
- USART1->CR3 |= (1<<6) ; /*DMA接收*/
- /*通道5是用作USART1的接收*/
- DMA1_Channel5->CCR = 0;
- DMA1_Channel5->CPAR = (u32)&(USART1->DR);
- DMA1_Channel5->CMAR = (u32)(UART_BUF.USART1_RX_BUF);
- DMA1_Channel5->CNDTR = DMA_CNDTR_RELOAD;
- DMA1_Channel5->CCR |= (1<<13)|(1<<12)|(1<<7)|(1<<1)|(1<<0); /*存储器地址增量 从外设读 循环模式 允许传输完成中断 启动传输通道*/
- MY_NVIC_Init(0,0,DMA1_Channel5_IRQChannel,2);
- #endif
-
- #endif
- }
- /*串口1 中断函数*/
- void USART1_IRQHandler(void)
- {
- u8 temp = USART1->SR;
- if(temp & (1<<4))
- {
- temp = USART1->DR;
- USART1->SR &= ~(1<<4);
- (void)temp; /*消除警告*/
-
- UART_BUF.USART1_RxCnt = DMA_CNDTR_RELOAD - DMA1_Channel5->CNDTR;
- // printf("CNDTR = %ld Rxcnt= %d ",DMA1_Channel5->CNDTR,UART_BUF.USART1_RxCnt); /*Printf函数不用的时候请注释掉,因为这家伙执行的时间比较长*/
- UART_BUF.USART1_STA |= 0x8000;
- DMA1_Channel5->CCR &= ~1; /*关闭DMA传输*/
- DMA1_Channel5->CNDTR = DMA_CNDTR_RELOAD; /*此处重新装载*/
- DMA1_Channel5->CCR |= 1; /*开启DMA传输*/
- #if DMA_USART1_TX
- DMA_UARTx_Enable(DMA1_Channel4,UART_BUF.USART1_RxCnt);
- #endif
- }
- }
- void DMA1_Channel4_IRQHandler(void) /*USART1->TX*/
- {
- //printf("SR= %#x \r\n",DMA1->ISR);
- DMA1->IFCR |= 0x7000 ;
- UART_BUF.USART1_STA = 0; /*记得要清0*/
- LED_G =!LED_G;
- DMA1_Channel4->CCR &= ~1;
- }
- void DMA1_Channel5_IRQHandler(void) /*USART1->RX*/
- {
- u32 temp =DMA1->ISR;
- if(temp & (1<<17)) /*传输完成标志*/
- {
- DMA1->IFCR |= (1<<17) ; /*清除传输完成*/
- LED_R =!LED_R;
- }
- LED_G =!LED_G;
- }
复制代码 ==================================- while(1)
- {
- // if(UART_BUF.USART1_STA & 0x8000)
- // Uartx_Send((const char *)&UART_BUF.USART1_RX_BUF,UART_BUF.USART1_RxCnt,USART1);
-
-
- }
复制代码 sscom 串口测试1ms没有问题,最大缓冲65532. ----------------不知道为什么,我设置的65535,只能接收到65532个
=============待续
备注:64K此处是极限,是不可能的,因为内存中还有其他数据要跑(STM32F103ZET 总共64K)。
建议粘贴到IDE看去。
PS: 音乐 普通英雄--毛宁,Touch By Touch,Sunny。 |
|