I've got an example code to turn on an LED with a button, it works. When I change it to send an spi command, it doesn't work anymore.
Could you check if you see something I did wrong with SPI? I've been around this issue for a day.
Thank you
#include <stdbool.h>
#include <stdint.h>
#include "nrf.h"
#include "nrf_gpiote.h"
#include "nrf_gpio.h"
#include "boards.h"
#include "nrf_drv_ppi.h"
#include "nrf_drv_timer.h"
#include "nrf_drv_gpiote.h"
#include "app_error.h"
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include "nordic_common.h"
#include "nrf.h"
//#include "nrf_delay.h"
#include "boards.h"
#include "app_error.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
//#include "SEGGER_RTT.h"
#include "nrf_drv_timer.h"
#include "nrf_drv_ppi.h"
#include "nrf_drv_spi.h"
#include "nrf_gpio.h"
#include "nrf_drv_gpiote.h"
//#define ACTIVE_CHANNEL 15
#define ACTIVE_CHANNEL 15
#define BYTES_PR_XFER_TX 4
// Number of bytes per transfer to receive from SPI slave
#define BYTES_PR_XFER_RX 4
// Number of SPI transfers to complete for one US frame
#define NUMBER_OF_XFERS 4
//#define DELAY_BETWEEN_TRANSFERS 1
// Max number of US frames to buffer
#define MAX_BUFFER_NUMBER_OF_US_FRAMES 35
#define LED_Pin1 3 // Pin connected with LED
#define Btn_Pin1 13 // Pin connected with Button
typedef struct ArrayList
{
uint8_t buffer[BYTES_PR_XFER_RX];
} ArrayList_type;
static ArrayList_type m_rx_buf[NUMBER_OF_XFERS*MAX_BUFFER_NUMBER_OF_US_FRAMES];
//extern ArrayList_type m_tx_buf_1[NUMBER_OF_XFERS];
static uint8_t m_tx_buf2[4];
void buffer_init(void)
{
m_tx_buf2[0] = 0x00;
m_tx_buf2[1] = ACTIVE_CHANNEL & 0x3F;
m_tx_buf2[2] = 0x00;
m_tx_buf2[3] = 0x00;
//m_tx_buf2[0] = 0xFF;
//m_tx_buf2[1] = 0xFF;
//m_tx_buf2[2] = 0xFF;
//m_tx_buf2[3] = 0xFF;
}
static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(0);
static nrf_ppi_channel_t ppi_channel; // A struct to hol ppi channel values
// Interrupt handler for GPIO button pin, we will not use it because we are directly routing
// the event to the pin, but you can use it in conjuction with the PPI
void intrrupt_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
// Empty handler
}
// Task and event addresses for SPI transactions
uint32_t start_spi_task_addr;
uint32_t spi_end_evt_addr;
uint32_t timer0_timeout_cc0_evt_addr;
uint32_t counter1_count_task_addr;
uint32_t counter1_cc0_evt_addr;
void spi_event_handler(nrf_drv_spi_evt_t const * p_event,
void * p_context)
{
// Never called if NRF_DRV_SPI_FLAG_NO_XFER_EVT_HANDLER flag is used
}
// @brief Handler for timer events.
void timer_timeout_event_handler(nrf_timer_event_t event_type, void* p_context)
{
// Handler must be declared and passed to nrf_drv_timer_init(),
// but is not used if nrf_drv_timer_extended_compare() is called with enable_int flag = false
}
/**@brief Function to initialize SPI
*
* @details This function initializes The SPI peripheral. It will also set up
* the SPI transfer with EasyDMA. The prepared SPI transfer can later be
* initiated with PPI.
*/
void spi_init()
{
uint32_t err_code;
nrf_drv_spi_config_t config = NRF_DRV_SPI_DEFAULT_CONFIG;
config.ss_pin = SPI_SS_PIN;
//LED_Pin1;
//SPI_SS_PIN;
config.miso_pin = SPI_MISO_PIN;
config.mosi_pin = SPI_MOSI_PIN;
config.sck_pin = SPI_SCK_PIN;
config.frequency = NRF_DRV_SPI_FREQ_8M;
config.bit_order = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST;
config.mode = NRF_DRV_SPI_MODE_1;
err_code = nrf_drv_spi_init(&spi, &config, spi_event_handler, NULL);
APP_ERROR_CHECK(err_code);
// Setting up an SPI transfer using EasyDMA
nrf_drv_spi_xfer_desc_t xfer = NRF_DRV_SPI_XFER_TRX(m_tx_buf2, BYTES_PR_XFER_TX, (uint8_t *)m_rx_buf, BYTES_PR_XFER_RX);
uint32_t flags = NRF_DRV_SPI_FLAG_HOLD_XFER |
NRF_DRV_SPI_FLAG_RX_POSTINC |
NRF_DRV_SPI_FLAG_REPEATED_XFER |
NRF_DRV_SPI_FLAG_NO_XFER_EVT_HANDLER;
err_code = nrf_drv_spi_xfer(&spi, &xfer, flags);
APP_ERROR_CHECK(err_code);
// Get SPI START task address and END event address
start_spi_task_addr = nrf_drv_spi_start_task_get(&spi);
spi_end_evt_addr = nrf_drv_spi_end_event_get(&spi);
}
//void spi_init()
//{
//}
// A function to initialize all the pins with all the configurations
static void gpiote_pins_init(void)
{
// Variable to hold error values
uint32_t error_code = NRF_SUCCESS;
error_code = nrf_drv_gpiote_init(); // Initialize gpiote module
APP_ERROR_CHECK(error_code);
// create the configurations for input pin interrupt
nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(true);
// set the PULL UP resistor because the button gives logic zero so when
// no button is being pressed the pullup resistors will pull the pin to logic high state
in_config.pull = NRF_GPIO_PIN_PULLUP;
// initialize the interrupt pin for the button
error_code = nrf_drv_gpiote_in_init(Btn_Pin1, &in_config, intrrupt_pin_handler);
APP_ERROR_CHECK(error_code);
// enable and configure the task of LED pin with its function
// it can be:
// set high
// set low
// or toggle pin
nrf_drv_gpiote_out_config_t out_config = GPIOTE_CONFIG_OUT_TASK_TOGGLE(true);
error_code = nrf_drv_gpiote_out_init(LED_Pin1, &out_config);
APP_ERROR_CHECK(error_code);
// once everything is done
// enable LED Pin task so that it can be executed when ever called by any event via PPI
nrf_drv_gpiote_out_task_enable(LED_Pin1);
// enable the interrupt event on button pin
nrf_drv_gpiote_in_event_enable(Btn_Pin1, true);
}
// A function to initialize the PPI Module with all the configurations
static void ppi_init(void)
{
// a variable to hold the error value
uint32_t err_code = NRF_SUCCESS;
// Variables to hold the event address and task address
// they are needed to connect with the PPI TEP(Task End Point) & PPI EEP (Event End Point)
uint32_t btn_evt_addr;
uint32_t led_task_addr;
// Initialize the PPI module, only to be enabled once
err_code = nrf_drv_ppi_init();
APP_ERROR_CHECK(err_code);
// Allocate the channel from the available PPI channels
err_code = nrf_drv_ppi_channel_alloc(&ppi_channel);
APP_ERROR_CHECK(err_code);
// Get the address of the respective event and tasks from the pins
btn_evt_addr = nrf_drv_gpiote_in_event_addr_get(Btn_Pin1);
led_task_addr = nrf_drv_gpiote_out_task_addr_get(LED_Pin1);
// connect the EEP & TEP with Peripheral Events & Tasks using their addresses and assign them to an allocated channel
//err_code = nrf_drv_ppi_channel_assign(ppi_channel, btn_evt_addr, led_task_addr);
err_code = nrf_drv_ppi_channel_assign(ppi_channel, btn_evt_addr, start_spi_task_addr);
APP_ERROR_CHECK(err_code);
// Enable the channel so that it can start receiving events and then route them to tasks
err_code = nrf_drv_ppi_channel_enable(ppi_channel);
APP_ERROR_CHECK(err_code);
}
//void test_spi_manually()
//{
// // Manually trigger the SPI START task
// *((volatile uint32_t *)start_spi_task_addr) = 1;
//}
int main(void)
{
buffer_init();
spi_init();
gpiote_pins_init();
ppi_init();
//test_spi_manually();
while (true)
{
// Do nothing
}
}
/** @} */