52832 PPI+SPI移植

5264 ワード

一、テストのプラットフォーム
この記事では、主にSPI機能をbleに移植する方法について説明します.app_hrs_pca10040_s 132工事上.
テストプラットフォーム全体は以下の通りです.
環境:win 10,64ビット、MDK集積開発環境.    SDK:nRF5_SDK_15.2プロトコルスタック:s 132_nrf52_6.1_softdevice.hex.ハードウェアプラットフォーム:pca 10040開発ボード.
二、動作原理
ここでは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再配置.
三、アプリケーション移植
1、関連Cファイルを追加する
TIMER、PPI、SPI、GPIOTEの4つの周辺機器に関するファイルを追加する必要があります
プロジェクトにnrfx_を追加するppi.c,nrf_drv_ppi.c,nrfx_spi.c,nrf_drv_spi.c,nrfx_spim.c,nrfx_gpiote.cこの6つのファイル
2、ヘッダファイルの追加
関連ヘッダファイルの追加
3、SPI関連コードを入れる
SPI通常モードはnRF 5_を参照できるSDK_15.2.0_9412 b 96examplesperipheralspiルーチンプロトコルスタックに移植する場合はsdk_config.hでSPIの割込み優先度を上げないと割込みに入れない.
SPIのPPIモードはプログラムを参照して作成することができます.
(1)SPI初期化
SPIのPPIモードでは、SCK、SIMO、SOMIの3つのピンのみが呼び出されます.したがって,片選脚は自分で高さを下げるか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; // DMA
    NRF_SPIM0->TXD.PTR=(uint32_t)&SPIWriteList; // buffer
    NRF_SPIM0->RXD.LIST=1; // DMA
    NRF_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);	// SPI
    nrf_drv_timer_enable(&m_timer1);// TIMER
}

(3)PPIイベント
ここには2つのPPIイベントがあり,イベント1はSPI開始およびGPIOTEをトリガし,イベント2はGPIOTEをトリガする.
void my_ppi_init(void)
{
    uint32_t err_code = NRF_SUCCESS;

    err_code = nrf_drv_ppi_init();//init PPI
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_timer_init(&m_timer1, NULL, timer_handler1);//init timer 1
    APP_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 spi
    APP_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);
}