本文主要是介绍52832 PPI+SPI移植,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一、测试的平台
本篇文章主要介绍将SPI功能移植到ble_app_hrs_pca10040_s132工程上。
整个测试平台如下:
环境:win10,64位,MDK集成开发环境.
SDK:nRF5_SDK_15.2
协议栈:s132_nrf52_6.1_softdevice.hex.
硬件平台:pca10040开发板.
二、工作原理
这里使用了SPI的PPI模式,能够极大的提高SPI的读写速度,减少MCU的干预,可以极大的节省功耗。当你对SPI的读写预先将NRF_SPIM0->TXD.PTR指向写buffer,将NRF_SPIM0->RXD.PTR指向读buffer。
每次进行SPI读写的时候,指针会自动往后移,当数据的长度达到buffer的长度时,需要将NRF_SPIM0->TXD.PTR和NRF_SPIM0->TXD.PTR重新置位。
三、Application移植
1、添加相关C文件
需要添加TIMER、PPI、SPI、GPIOTE四个外设的相关文件
在工程中添加nrfx_ppi.c,nrf_drv_ppi.c,nrfx_spi.c,nrf_drv_spi.c,nrfx_spim.c,nrfx_gpiote.c这六个文件
2、添加头文件
添加相关头文件
3、加入SPI相关代码
SPI普通模式可以参考nRF5_SDK_15.2.0_9412b96\examples\peripheral\spi例程,在移植到协议栈中时,要注意在sdk_config.h中提高SPI的中断优先级,否则会无法进入中断。
SPI的PPI模式可以参照一下程序去编写:
(1)SPI初始化
在SPI的PPI模式中,只会调用到SCK,SIMO,SOMI这三个引脚。所以片选脚要自己去拉低拉高或者配置为GPIOTE模式,使用PPI去触发GPIOTE事件。
void ADC_SPIDMA_Init (void) //初始化SPI DMA相关参数
{ NRF_SPIM0->TXD.MAXCNT = 2;//每次写两个字节 (16位寄存器)NRF_SPIM0->RXD.MAXCNT = 2;//每次读两个字节 (16位数据)NRF_SPIM0->TXD.LIST=1; //开启写DMANRF_SPIM0->TXD.PTR=(uint32_t)&SPIWriteList; //指向写bufferNRF_SPIM0->RXD.LIST=1; //开启读DMANRF_SPIM0->RXD.PTR=(uint32_t)&SPIReadList1; //指向读buffer
}void CS_Gpiote_Init(void) //初始化片选脚,一定要使用GPIOTE模式
{ uint32_t err_code; nrf_drv_gpiote_out_config_t config = GPIOTE_CONFIG_OUT_TASK_TOGGLE(true); //设置为切换触发err_code = nrf_drv_gpiote_out_init(SPI_SS_PIN, &config); //设置GPIOTE引脚APP_ERROR_CHECK(err_code); // nrf_drv_gpiote_out_task_enable(SPI_SS_PIN); //使能GPIOTE事件nrf_drv_gpiote_out_set(SPI_SS_PIN); //
}void spi_init(void)
{nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
// spi_config.ss_pin = SPI_SS_PIN;spi_config.miso_pin = SPI_MISO_PIN;spi_config.mosi_pin = SPI_MOSI_PIN;spi_config.sck_pin = SPI_SCK_PIN;APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event, NULL));CS_Gpiote_Init();ADC_SPIDMA_Init();
}
(2)SPI中断事件
当数据达到指定长度时重新置位指针。
void spi_event(nrf_drv_spi_evt_t const * p_event,void * p_context)
{spi_count++;if(spi_count==80)//buffer长度{spi_count=0; NRF_SPIM0->TXD.PTR=(uint32_t)&SPIWriteList;//重新将指针指回起始地址NRF_SPIM0->RXD.PTR=(uint32_t)&SPIReadList1;//将指针指回起始地址}
}
也可以加入开关控制,避免数据被覆盖。
当检测到send_flag置1时,进行相关数据的读取,读完数据再调用SPI_start进行SPI的相关使能。
中间可以调用SPI_stop失能SPI和定时器,这样可以节省大部分的功耗。
void spi_event(nrf_drv_spi_evt_t const * p_event,void * p_context)
{spi_count++;if(spi_count==80){nrf_drv_timer_pause(&m_timer1);//暂停PPI触发定时器spi_count=0; send_flag = 1;}
}void SPI_reset_buff(void)
{spi_count = 0;NRF_SPIM0->TXD.PTR=(uint32_t)&SPIWriteList;NRF_SPIM0->RXD.PTR=(uint32_t)&SPIReadList1;
}void SPI_stop(void)
{nrf_drv_timer_disable(&m_timer1);nrf_spim_disable(NRF_SPIM0);
}void SPI_start(void)
{SPI_reset_buff();//复位指针nrf_spim_enable(NRF_SPIM0); //使能SPInrf_drv_timer_enable(&m_timer1);//使能TIMER
}
(3)PPI事件
这里一共有两个PPI事件,事件1是触发SPI开始以及GPIOTE,事件2是触发GPIOTE
void my_ppi_init(void)
{uint32_t err_code = NRF_SUCCESS;err_code = nrf_drv_ppi_init();//init PPIAPP_ERROR_CHECK(err_code);err_code = nrf_drv_timer_init(&m_timer1, NULL, timer_handler1);//init timer 1APP_ERROR_CHECK(err_code);/* setup m_timer for compare event every 15us */uint32_t ticks = nrf_drv_timer_us_to_ticks(&m_timer1, 15);nrf_drv_timer_extended_compare(&m_timer1, NRF_TIMER_CC_CHANNEL0, ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false);//设置比较时间nrf_drv_timer_enable(&m_timer1);//使能定时器uint32_t timer_compare_event_addr = nrf_drv_timer_compare_event_address_get(&m_timer1, NRF_TIMER_CC_CHANNEL0);uint32_t spi_start_event_addr = nrf_drv_spi_start_task_get(&spi);uint32_t spi_end_event_addr = nrf_drv_spi_end_event_get(&spi);uint32_t gpiote_out_event_addr = nrf_drv_gpiote_out_task_addr_get(SPI_SS_PIN);/* setup ppi channel so that timer compare event is triggering sample task in SAADC */err_code = nrf_drv_ppi_channel_alloc(&time_ppi_channel);APP_ERROR_CHECK(err_code);err_code = nrf_drv_ppi_channel_assign(time_ppi_channel, timer_compare_event_addr, gpiote_out_event_addr);//timer触发gpiote,片选脚拉低APP_ERROR_CHECK(err_code);err_code=nrf_drv_ppi_channel_fork_assign(time_ppi_channel,spi_start_event_addr);//timer触发spiAPP_ERROR_CHECK(err_code);err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel);APP_ERROR_CHECK(err_code);err_code = nrf_drv_ppi_channel_assign(m_ppi_channel, spi_end_event_addr, gpiote_out_event_addr);//spi结束触发gpiote,片选脚拉高APP_ERROR_CHECK(err_code);err_code = nrf_drv_ppi_channel_enable(time_ppi_channel);APP_ERROR_CHECK(err_code);err_code = nrf_drv_ppi_channel_enable(m_ppi_channel);APP_ERROR_CHECK(err_code);
}
这篇关于52832 PPI+SPI移植的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!