版权声明:本文为博主原创文章,保留最终解释权,转载请注明出处。
【问题】:测试Timer每次通过PPI触发SPI写,SPI写完调用回调函数,回调函数中测试 NRF_SPIM2->TXD.PTR 的每次都是正常递增变化的,但是DAC就是没有实际的输出;
PS:1、要写的源数据测试是正确的;
2、为了不频繁占用CPU资料,用的PPI,用上后 timer+PPI+SPI(DMA) 写DAC 一直没调通,不加PPI的timer+SPI 写DAC 是OK的;
【原因】:进一步测试发现CS始终为高电平,手动飞线拉低CS再放开,DAC才有输出,判断为CS控制异常原因导致,而nRF52832的硬件SPI没有CS功能,SPI发送前需要软件设置CS为低,而设计中采用的是PPI触发,全硬件运行,没有软件可以控制CS电平变化,所以,CS一直为高;
【解决方案】:
1、TIMER+PPI+SPI(DMA)& CS中,PPI的二级任务端点 设置成CS pin(使用GPIOTE功能实现)后,使Timer 通过PPI触发 CS拉低+ SPI写;
2、要使SPI传输完成后CS拉高,所以再加一个PPI,EEP为SPI 传输完成,TEP为CS IO口的电平toggle;
【源码】:
【执行函数顺序】 1、Timer_Initial_DA_Freq(); 2、DAC_SPI_Init(); 3、Dac_PPI_Config(); 【其他功能函数】 //控制 CS,因硬件PPI触发SPI,没有软件控制CS情况下,CS一直为高电平 void CS_Gpiote_Init(void) { ret_code_t err_code; //初始化GPIOTE程序模块 if(GPIOTE_init==0) { err_code = nrf_drv_gpiote_init(); APP_ERROR_CHECK(err_code); GPIOTE_init=1; printf("GPIOTE Init OK \r\n"); } //定义GPIOTE输出初始化结构体,并对其成员变量赋值 nrf_drv_gpiote_out_config_t config = GPIOTE_CONFIG_OUT_TASK_TOGGLE(true); //初始化GPIOTE输出引脚,初始化时会分配一个GPIOTE通道 err_code = nrf_drv_gpiote_out_init(DAC_SPI_SS, &config); APP_ERROR_CHECK(err_code); //使能引脚 所在GPIOTE通道的任务触发 nrf_drv_gpiote_out_task_enable(DAC_SPI_SS); nrf_drv_gpiote_out_set(DAC_SPI_SS); } /**************************************************************************************** * 描 述 : dac_ppi_config函数,这里我们通过库函数来编写PPI代码,需要注意的是PPI通道是由驱动函数分配的。 调用nrf_drv_ppi_channel_alloc函数后,该函数会把第一个找到的空闲PPI通道分配给应用程序。 * 入 参 : 无 * 返回值 : 无 ***************************************************************************************/ void Dac_PPI_Config(void) { uint32_t err_code = NRF_SUCCESS; //初始化PPI程序模块 err_code = nrf_drv_ppi_init(); APP_ERROR_CHECK(err_code); //分配PPI通道,注意PPI通道的分配是由驱动函数完成的,分配的通道号保存到my_ppi_channel err_code = nrf_drv_ppi_channel_alloc(&timer2DAC_ppi_channel); APP_ERROR_CHECK(err_code); //分配PPI通道的EEP和TEP err_code = nrf_drv_ppi_channel_assign(timer2DAC_ppi_channel, nrf_drv_timer_compare_event_address_get(&TIMER_DAC,NRF_TIMER_CC_CHANNEL0), nrf_drv_gpiote_out_task_addr_get(DAC_SPI_SS)); APP_ERROR_CHECK(err_code); err_code = nrf_drv_ppi_channel_fork_assign(timer2DAC_ppi_channel, nrf_drv_spi_start_task_get(&DAC_spi)); APP_ERROR_CHECK(err_code); //使能PPI通道 err_code = nrf_drv_ppi_channel_enable(timer2DAC_ppi_channel); APP_ERROR_CHECK(err_code); //SPI 结束触发 CS 拉高 err_code = nrf_drv_ppi_channel_alloc(&CS_ppi_channel); APP_ERROR_CHECK(err_code); err_code = nrf_drv_ppi_channel_assign(CS_ppi_channel, nrf_drv_spi_end_event_get(&DAC_spi), nrf_drv_gpiote_out_task_addr_get(DAC_SPI_SS) ); APP_ERROR_CHECK(err_code); //使能PPI通道 err_code = nrf_drv_ppi_channel_enable(CS_ppi_channel); APP_ERROR_CHECK(err_code); printf("PPI enable OK \r\n"); nrf_drv_timer_enable(&TIMER_DAC); printf("nrf_drv_timer_enable OK \r\n"); } //初始化Timer定时器,设置正弦波频率函数 //Freq :输出的正弦波频率 Hz //Num :一周期正弦波点数 void Timer_Initial_DA_Freq(uint32_t Freq,uint16_t Num) { //定义定时器配置结构体,并使用默认配置参数初始化结构体 nrf_drv_timer_config_t timer_cfg =NRF_DRV_TIMER_DEFAULT_CONFIG; //初始化定时器,初始化时会注册timer_led_event_handler事件回调函数 err_code = nrf_drv_timer_init(&TIMER_DAC, &timer_cfg, timer_DAC_event_handler); APP_ERROR_CHECK(err_code); //定时时间(单位us)转换为ticks time_ticks = nrf_drv_timer_us_to_ticks(&TIMER_DAC, time_us); printf("time_us= %d,time_ticks= %d \r\n",time_us,time_ticks); //设置定时器捕获/比较通道及该通道的比较值,使能通道的比较中断 nrf_drv_timer_extended_compare( &TIMER_DAC, NRF_TIMER_CC_CHANNEL0, time_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false); } //Timer事件回调函数 void timer_DAC_event_handler(nrf_timer_event_t event_type, void* p_context) { } //基于nRF52832硬件SPI 函数 void spi_event_handler(nrf_drv_spi_evt_t const * p_event) { uint8_t i=0; DAC_COUNT++; if(DAC_COUNT==DAC_NUMBER) { DAC_COUNT=0; NRF_SPIM2->TXD.PTR=(uint32_t)&SPI2ArrayList; } } //SPI initialization void DAC_SPI_Init (void) { /* 初始化SPI2 */ nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG; spi_config.mosi_pin = DAC_SPI_MOSI; spi_config.sck_pin = DAC_SPI_SCK; CS_Gpiote_Init(); spi_config.frequency= NRF_SPI_FREQ_8M; APP_ERROR_CHECK(nrf_drv_spi_init(&DAC_spi, &spi_config, spi_event_handler)); DAC_SPIDMA_Init(); printf("DAC_SPI_Init OK \r\n"); nrf_delay_ms(500); } //正弦函数表sine_wave16bit的数据转换,并关联SPI DMA缓存 void DAC_SPIDMA_Init (void) { uint8_t i=0; uint8_t temp_H,temp_L; for(i=0;i<DAC_NUMBER;i++) //格式转换 { temp_H=(uint8_t)(sine_wave16bit[i]>>8); //取高4位 temp_L=(uint8_t)sine_wave16bit[i]; //取低8位 SPI2ArrayList[i].buffer[0]=DAC_WriteDAC_CMD | temp_H; SPI2ArrayList[i].buffer[1]=temp_L; } //关联SPI DMA缓存 NRF_SPIM2->TXD.MAXCNT = 2; NRF_SPIM2->RXD.MAXCNT = 2; NRF_SPIM2->TXD.LIST=1; NRF_SPIM2->TXD.PTR=(uint32_t)&SPI2ArrayList; //SPI2ArrayList; }