nRF52832 Timer+PPI+SPI 全硬體觸發方式控制DAC,減少CPU干預,效率極大提升
阿新 • • 發佈:2018-12-15
【問題】:測試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_Initial_DA_Freq(); 2、MCP4821_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; }