I am using Timer0 and Timer with GPIOTE and PPI to output 2 clocks on 2 pins.
Both timer settings are identical (for troubleshooting). Only timer-0 can be generated at the output pins (pin-1 and pin-2). While timer-1 does not produce any output.
(after spending 10+ hours of testing, and missing a deadline, and checking that both timers are enabled in the sdk_config.h)
any clue what can be the reason ?
/*
Use Timer with PPI and GPIOTE
Generates 4MHz timer on output pin
Timer1 is not outputting
*/
#include <stdbool.h>
#include <stdint.h>
#include "nrf.h"
#include "app_error.h"
#include "nrfx_gpiote.h"
#include "nrf_gpiote.h"
#include "nrf_gpio.h"
#include "nrf_drv_gpiote.h"
#include "nrf_ppi.h"
#include "nrf_drv_ppi.h"
#include "nrf_drv_timer.h"
#include "boards.h"
#include "nrf_drv_gpiote.h"
#define I2S_SCK NRF_GPIO_PIN_MAP(0,13)
#define I2S_LRCLK NRF_GPIO_PIN_MAP(0,3)
#define LED_Power NRF_GPIO_PIN_MAP(1,9)
// Create variable to hold error values
ret_code_t err_code;
// Create timer instance
const nrf_drv_timer_t Timer_0 = NRF_DRV_TIMER_INSTANCE(0);
const nrf_drv_timer_t Timer_1 = NRF_DRV_TIMER_INSTANCE(1);
// Create Timer ISR handler
void Timer_0_handler(nrf_timer_event_t event_type, void* p_context)
{
}
void Timer_1_handler(nrf_timer_event_t event_type, void* p_context)
{
}
// A function to initialize and set everything for the timers with PPI and GPIOTE
static void Initialize_Timer_PPI_GPIOTE(void)
{
//NRF_CLOCK->TASKS_HFCLKSTART = 1;
// while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0)
// {
// // Wait for clock to start
// }
// Configure timer as counter, 64 counts at 4MHz
nrf_drv_timer_config_t Timer_0_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
Timer_0_cfg.frequency = NRF_TIMER_FREQ_8MHz;
//Timer_0_cfg.mode = NRF_TIMER_MODE_COUNTER;
//Timer_0_cfg.bit_width = TIMER_BITMODE_BITMODE_32Bit;
// Set up timer
NRF_TIMER0->PRESCALER = 1;
NRF_TIMER0->CC[0] = 1; // Adjust the output frequency by adjusting the CC.
//NRF_TIMER0->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos;
NRF_TIMER0->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Enabled;
//NRF_TIMER0->TASKS_START = 1;
// Configure timer as counter, 2 counts at 62.5KHz
nrf_drv_timer_config_t Timer_1_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
Timer_1_cfg.frequency = NRF_TIMER_FREQ_4MHz;
//Timer_1_cfg.mode = NRF_TIMER_MODE_COUNTER;
//Timer_1_cfg.bit_width = TIMER_BITMODE_BITMODE_32Bit;
// Set up timer
NRF_TIMER1->PRESCALER = 0;
NRF_TIMER1->CC[1] = 1; // Adjust the output frequency by adjusting the CC.
//NRF_TIMER1->SHORTS = TIMER_SHORTS_COMPARE1_CLEAR_Enabled << TIMER_SHORTS_COMPARE1_CLEAR_Pos;
NRF_TIMER1->SHORTS = TIMER_SHORTS_COMPARE1_CLEAR_Enabled;
//NRF_TIMER1->TASKS_START = 1;
// Initialize timers
err_code = nrf_drv_timer_init(&Timer_0, &Timer_0_cfg, Timer_0_handler);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_timer_init(&Timer_1, &Timer_1_cfg, Timer_1_handler);
APP_ERROR_CHECK(err_code);
// Create variables to hold event and task addresses. They will connect with PPI TEP (Task End Point) and PPI EEP (Event End Point)
uint32_t compare_event_addr_1;
uint32_t compare_event_addr_2;
uint32_t gpiote_task_addr_1;
uint32_t gpiote_task_addr_2;
// Create structure to hold PPI channel values
nrf_ppi_channel_t ppi_channel_1;
nrf_ppi_channel_t ppi_channel_2;
// Initialize GPTIOTE module
if(!nrf_drv_gpiote_is_init())
{
err_code = nrf_drv_gpiote_init();
APP_ERROR_CHECK(err_code);
}
// Initialize PPI module, make sure it is only enabled once in the code
err_code = nrf_drv_ppi_init();
APP_ERROR_CHECK(err_code);
// Allocate a channel from available PPI channels
err_code = nrf_drv_ppi_channel_alloc(&ppi_channel_1);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_ppi_channel_alloc(&ppi_channel_2);
APP_ERROR_CHECK(err_code);
// Enable and configure the pin (high/low/toggle). True ? Initial high state, False ? Initial low state
nrf_drv_gpiote_out_config_t out_config_1 = GPIOTE_CONFIG_OUT_TASK_TOGGLE(false);
err_code = nrf_drv_gpiote_out_init(I2S_SCK, &out_config_1);
APP_ERROR_CHECK(err_code);
nrf_drv_gpiote_out_config_t out_config_2 = GPIOTE_CONFIG_OUT_TASK_TOGGLE(false);
err_code = nrf_drv_gpiote_out_init(I2S_LRCLK, &out_config_2);
APP_ERROR_CHECK(err_code);
// Get address of respective event and tasks from the respective peripherals
compare_event_addr_1 = nrf_drv_timer_event_address_get(&Timer_0, NRF_TIMER_EVENT_COMPARE0);
gpiote_task_addr_1 = nrf_drv_gpiote_out_task_addr_get(I2S_SCK);
compare_event_addr_2 = nrf_drv_timer_event_address_get(&Timer_1, NRF_TIMER_EVENT_COMPARE1);
gpiote_task_addr_2 = nrf_drv_gpiote_out_task_addr_get(I2S_LRCLK);
// Connect EEP & TEP with Peripheral Events and Tasks using their addresses and assign them to an allocated channel
err_code = nrf_drv_ppi_channel_assign(ppi_channel_1, compare_event_addr_1, gpiote_task_addr_1);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_ppi_channel_assign(ppi_channel_2, compare_event_addr_2, gpiote_task_addr_2);
APP_ERROR_CHECK(err_code);
// Enable channel to start receiving events and route them to tasks
err_code = nrf_drv_ppi_channel_enable(ppi_channel_1);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_ppi_channel_enable(ppi_channel_2);
APP_ERROR_CHECK(err_code);
// Enable pin task to be executed when called by any event via PPI
nrf_drv_gpiote_out_task_enable(I2S_SCK);
nrf_drv_gpiote_out_task_enable(I2S_LRCLK);
}
int main(void)
{
nrf_gpio_cfg_output(I2S_SCK);
nrf_gpio_cfg_output(I2S_LRCLK);
nrf_gpio_cfg_output(LED_Power);
nrf_gpio_pin_clear(I2S_SCK);
nrf_gpio_pin_clear(I2S_LRCLK);
nrf_gpio_pin_set(LED_Power);
Initialize_Timer_PPI_GPIOTE();
// Start timer
nrf_drv_timer_enable(&Timer_0);
nrf_drv_timer_enable(&Timer_1);
while (1)
{
// __WFI();
}
}