CC2540串口驱动问题咨询
下午好啊,各位坛友!
官方提供的例程中有串口的驱动、读、写等函数,用起来挺方便的。但是这部分驱动看起来一点也不比协议栈简单啊。。。改起来也有些难度!有没有专门这方面的资料说明呢?
例程中的串口接收是通过DMA轮询,并将事件反馈到用户注册的回调函数中。串口的接收必须有时钟信号的支持,这样CPU就无法睡眠了。
NPI_InitTransport(NPI_SerialCallback);//注册串口事件回调函数
我有个想法,不知是否行得通:在外部(MCU与CC2540串口通信)发送串口数据前拉低CC2540一个引脚的电平,通过外部中断来唤醒CC2540,而CC2540中断后则保持CPU不睡眠,直到数据接收完毕再进行睡眠。例程中的串口接收能否支持这样的工作方式呢?
shaokai,
DMA 必须要有时钟信号。
可以,你可以用一个GPIO 唤醒系统再去搬运UART 数据。但注意,最好是先让外部MCU 通过GPIO 唤醒2540, 然后MCU再向UART 口发送数据,以免前几个字节数据丢失。
Yan,
我快被驱动搞疯了,我在预处理器定义使用了串口驱动HAL_UART=TRUE和节能模式POWER_SAVING。
这下好,编译警告地址为0X6B的中断向量重复定义。打开_hal_uart_dma.c一看,莫名其妙的多了个P0口的中断处理函数,而我在按键模块已定义过P0口的中断处理函数。
看了下预编译,只有在#if (HAL_UART_DMA == 1),且定义了POWER_SAVING 才会增加P0中断处理函数的编译。
HAL_ISR_FUNCTION(port0Isr, P0INT_VECTOR)
我不太明白,为何要在这里增加这个中断处理函数?可以去掉吗?调的真想哭啊。。。
shaokai,
HAL_UART_DMA == 1 的时候, UART 会用DMA 模式搬运数据。你这个应该不是因为 POWER_SAVING,是因为DMA。
这个中断处理不能去除。
你看一下是否其他地方有重定义了0X6B 向量的中断处理,比如按键或者其他IO 之类,然后换个其他中断向量就行。
Yan,
DMA搬运数据为什么跟P0口的外部中断有关系呢?这点不是很明白。
另外,在simpleBLEPeripheral这个工程中似乎并未加入_hal_uart_dma.c这个文件(工程栏目中找不到),只是在Option->C/C++ Complier->Preprocessor中有这个链接关系:$PROJ_DIR$\..\..\..\..\Components\hal\target\CC2540EB。
我是在自己写的中断处理函数处,右击P0INT_VECTOR后通过Find All References of 'P0INT_VECTOR' 跳转到这个文件的。
既然_hal_uart_dma.c未加入工程,我想应该不会影响编译吧(编译器应该只是编译已加入工程的文件)?——但是会警告,不解~~~
Yan
串口初始化时,需要注册用户处理串口事件的回调函数。
NPI_InitTransport(NPI_UART_CB);
我在回调函数中,检测收到的事件。在屏蔽POWER_SAVING的情况下,发送完数据可以收到HAL_UART_TX_EMPTY的事件,但是一旦使能POWER_SAVING则收不到这个事件。这是为什么呢?难道DMA中数据还未发送完又进入睡眠状态了?
void NPI_UART_CB(uint8 port,uint8 event)
{
if(event & HAL_UART_TX_EMPTY)//发送空
{
FrameTxState = Finish;
HalLedSet(HAL_LED_2,HAL_LED_MODE_TOGGLE);
}
if(event & HAL_UART_RX_TIMEOUT)//有数据等待接收
{
}
}
为此我还修改了部分代码:
uint16 NPI_WriteTransport( uint8 *buf, uint16 len )
{
FrameTxState = Doing;
return( HalUARTWrite( NPI_UART_PORT, buf, len ) );
}
OSAL.C中修改了void osal_run_system( void )
{
#if defined( POWER_SAVING )
else // Complete pass through all task events with no activity?
{
if(FrameTxState == Finish)
{
HalLedSet(HAL_LED_1,HAL_LED_MODE_ON);
osal_pwrmgr_powerconserve(); // Put the processor/system into sleep
}
}
#endif
}
其他地方没有改变,数据就是发不出去,还是失败了。
我想知道,如何使DMA数据发送完了才进入睡眠?
shaokai,
首先,DMA 是需要clock 才能工作的。如果有POWER_SAVING,那么就会有可能把外部晶振关闭,那么DMA就不工作了。
P0 中断是UART 中断,因为你用的是P0 口来配置UART。UART 挂在在P0上。
请不要修改osal_run_system()里面的东西,特别涉及到power management的代码,因为这是系统自动来控制的。
你可以尝试 用 osal_pwrmgr_device( ); 参数有 PWRMGR_BATTERY 和 PWRMGR_ALWAYS_ON, 用这个来尝试一下模式变换。
Yan,
还是有问题啊:在初始化时,打印就没问题
NPI_InitTransport(NPI_UART_CB);
NPI_WriteTransport("Hello\n\0",7);
但是后面的按键响应打印还是无数据
if ( keys & HAL_KEY_SW_1 )
{
SK_Keys |= SK_KEY_LEFT;
NPI_WriteTransport("Key1 SP\n",8);
}
if ( keys & HAL_KEY_SW_2 )
{
NPI_WriteTransport("Key2 SP\n",8);
SK_Keys |= SK_KEY_RIGHT;
...
}
把POWER_SAVING屏蔽了,就OK。给我的感觉就是一旦睡眠过,DMA就无法再收发数据了。
我试过用PWRMGR_ALWAYS_ON也不行。
shaokai,
理论上,你只要在打印之前,唤醒32M 晶振,然后用PWRMGR_ALWAYS_ON,那应该是没有问题的。
建议你debug 打印的时候,还是把POWER_SAVING 关闭,然后关闭debug的时候,以正常的POWER_SAVING模式运行。
Yan
我不是在debug时候跟踪打印的,我把程序改好了,烧到2540里跑的。
我试过POWER_SAVING,并在打印之前,使用PWRMGR_ALWAYS_ON。还是无效啊。只能屏蔽POWER_SAVING.
hi, shaokai Lin
我碰到的问题跟你是一样的,就算一开始就打开PWRMGR_ALWAYS_ON也不行,只能发个两三秒钟,后面就再也发不了了。你现在解决了这个问题没?
嗯啊~
太久没弄,有些都忘了,不过你要注意以下几点:
1. 启动后开启一个周期任务,osal_start_timerEx(UserTask_ID,USER_PERIOD,1000);//保证CPU不会进入到PM3模式,周期可以设大一点
2.还有就是修改下DMA的一个宏定义,把 #define DMA_PM 1 改为 #define DMA_PM 0
您好,
我之前的UART驱动,之前有分享一篇帖子
http://www.deyisupport.com/question_answer/wireless_connectivity/bluetooth/f/103/t/61462.aspx
里面的串口透传程序就是使用的这个驱动,请参考。
上传头文件