Hi there, I am trying to do a blocking simple ADC measurement in using NRFX drivers in a threaded context, however when I build I get the following error:
gen_isr_tables.py: error: multiple registrations at table_index 14 for irq 14 (0xe)
Existing handler 0xd34d, new handler 0x5bfd
Has IRQ_CONNECT or IRQ_DIRECT_CONNECT accidentally been invoked on the same irq multiple times?
ninja: build stopped: subcommand failed.
But as you can see in my code that I define my IRQ_CONNECT for two separate interrupt functions, if I comment out the interrupt connect the code builds however the ADC does not sample. If i step through in debug mode the ADC does sample, could I please have some assistance with this issue?
/*
* Copyright (c) 2022 - 2023, Nordic Semiconductor ASA
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "hal/nrf_pwm.h"
#include <nrfx_example.h>
#include <nrfx_pwm.h>
#include <stdbool.h>
#include <stdint.h>
//#include <zephyr/drivers/adc.h>
#include <zephyr/drivers/pwm.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include "drivers/nrfx_errors.h"
#include <nrfx_glue.h>
#include <nrfx_saadc.h>
//#include "saadc_examples_common.h"
#define NRFX_LOG_MODULE EXAMPLE
#define NRFX_EXAMPLE_CONFIG_LOG_ENABLED 1
#define NRFX_EXAMPLE_CONFIG_LOG_LEVEL 3
#include <nrfx_log.h>
/**
* @defgroup nrfx_pwm_common_example Common mode PWM example
* @{
* @ingroup nrfx_pwm_examples
*
* @brief Example showing basic functionality of nrfx_pwm driver for sequence loaded in common mode.
*
* @details Application initializes nrfx_pmw driver. It plays a simple sequence on LEDs ("breath"
* effect) and replays this sequence @ref NUM_OF_LOOPS times. The @ref pwm_handler() is
* executed with relevant log message after every loop.
*/
/** @brief Symbol specifying PWM instance to be used. */
#define STACKSIZE 1024
#define THREAD0_PRIORITY 7
#define THREAD1_PRIORITY 7
#define PWM_INST_IDX 0
#define ARRAYSIZE 192
//#define CH0_AIN ANALOG_INPUT_TO_SAADC_AIN(ANALOG_INPUT_A0)
/**
* @brief Symbol specifying number of times that each duty cycle is to be repeated (after being
* played once) and is strictly correlated with the "breath" effect speed.
*/
#define VALUE_REPEATS 0UL
/** @brief Symbol specifying number of loops (breaths) to be performed. */
#define NUM_OF_LOOPS 1UL
/**
* @brief Symbol specifying number of playbacks to be performed. In this example couple of
* playbacks might be considered as one loop.
*/
#define PLAYBACK_COUNT 1UL
//create a global PWM instance
nrfx_pwm_t pwm_instance1 = NRFX_PWM_INSTANCE(PWM_INST_IDX);
// Global PWM configuration setup
// 1 PWM period is 1.25us, clcok period is 62.5ns
// automatic stepping
nrfx_pwm_config_t config1 = {
.output_pins = {LED1_PIN, LED2_PIN, LED3_PIN, LED4_PIN},
.pin_inverted = {0, 0, 0, 0},
.irq_priority = 7,
.base_clock = NRF_PWM_CLK_16MHz,
.count_mode = NRF_PWM_MODE_UP,
.top_value = 20,
.load_mode = NRF_PWM_LOAD_COMMON,
.step_mode = NRF_PWM_STEP_AUTO,
.skip_gpio_cfg = 0
};
// Mutex definition of variable synchronisation/ control over critical code section timing
K_MUTEX_DEFINE(key);
nrf_pwm_values_common_t pwm_val []=
{
0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 13, 6, 13, 6, 13, 6, 6, 13, 13, 13, 13, 6, 13
};
static nrf_pwm_values_common_t reset_seq [55] = {0};
nrf_pwm_values_common_t pwm_array_val [192] = {0};
nrf_pwm_values_common_t pwm_array_val2 [192] = {0};
// Led Array Build Function:
/*
Inputs:
nrf_pwm__values_common_t *array: Pointer to array[0] to store signal PWM duty cycles as one big block to send as a continouse signal
int lednumber: number where it sits in the LED strip 0-7 to place the colour sequnce in teh correct order
nrf_pwm__values_common_t *coloursignal: pointer to coloursignal[0] which is the 24 element array that holds the colour value for 1 LED
Outputs:
none
Description:
concatenates each LED colour setup array as one big block of a pwm duty cycle sequence to be sent as a continous signal due to the WS2812 signalling
*/
void ledarraybuild(nrf_pwm_values_common_t *array,int lednumber,nrf_pwm_values_common_t *coloursignal){
int base;
base = 24*lednumber;
for(int i = 0; i < 24; i++){
array[base + i] = coloursignal[i];
}
return;
}
// Colour Sequence Function:
/*
Inputs:
nrf_pwm__values_common_t *val: Pointer to val[0], which is a 24 element array of uint16_t values to store individual duty cycles in
uint8_t red: Red component of a colour RGB hex code for ease of use
uint8_t green: Green component of a colour RGB hex code for ease of use
uint8_t blue: Blue component of a colour RGB hex code for ease of use
Outputs:
none
Description:
Adds appropriate duty cycle values in an array to represent a colour for one LED from a hex code
to match the WS2812 signalling protocol. This is inverted as it appears the PWM signal has an
an inversion at some point. High should be VH for ~800ns, Low should be VH for ~400ns, this is designated
from the hex code with the correct ordering as well.
*/
void colour_sequence(nrf_pwm_values_common_t *val, uint8_t red, uint8_t green, uint8_t blue){
for(int i = 7; i >= 0; i--){
//redblock
if((red&(0x80>>i))){
val[i + 8] = 6;
} else {
val[i + 8] = 14;
}
// blue block
if((blue&(0x80>>i))){
val[i + 16] = 6;
} else {
val[i + 16] = 14;
}
// green block
if((green&(0x80>>i))){
val[i] = 6;
} else {
val[i] = 14;
}
}
return;
}
//once PWM has a loop event this is triggered to setup a looped PWM.-> we need to change this to not be looping
//currently set to only loop once
static void pwm_handler(nrfx_pwm_evt_type_t event_type, void * p_context)
{
nrfx_pwm_t * inst = p_context;
/*switch(event_type){
case NRFX_PWM_EVT_STOPPED:
break;
}*/
static uint32_t curr_loop = 1;
NRFX_LOG_INFO("Loops: %u / %lu", curr_loop, NUM_OF_LOOPS);
if (curr_loop == NUM_OF_LOOPS)
{
NRFX_LOG_INFO("PWM finished");
nrfx_pwm_uninit(inst);
}
curr_loop++;
}
static void ledupdate(uint16_t highcolour, uint16_t lowcolour, int level){
static nrf_pwm_values_common_t pwm_array_val [192] = {0};
nrf_pwm_sequence_t const seq_set =
{
.values = {pwm_array_val},
.length = NRFX_ARRAY_SIZE(pwm_array_val),
.repeats = VALUE_REPEATS,
.end_delay = 0
};
for(int i = 0; i < 8; i++){
colour_sequence(pwm_val, 0x0F, 0x00, 0x00);
ledarraybuild(pwm_array_val, i, pwm_val);
}
for(int i = 0; i < level; i++){
colour_sequence(pwm_val, 0x00, 0x00, 0x0F);
ledarraybuild(pwm_array_val, i, pwm_val);
}
//NRF_PWM0->SEQ = &pwm_array_val;
nrfx_pwm_simple_playback(&pwm_instance1, &seq_set, PLAYBACK_COUNT, NRFX_PWM_FLAG_LOOP);
//nrfx_pwm_stop(&pwm_instance, true);
//nrfx_pwm_sequence_update(&pwm_instance, 0,&seq_set);
return;
}
//Thread to change the colour based on the ADC value/ Temperature
void thread0(void)
{
#if defined(__ZEPHYR__)
IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_PWM_INST_GET(PWM_INST_IDX)), IRQ_PRIO_LOWEST,
NRFX_PWM_INST_HANDLER_GET(PWM_INST_IDX), 0, 0);
#endif
nrfx_err_t status;
(void) status;
//NRFX_EXAMPLE_LOG_INIT();
//NRFX_LOG_INFO("Starting nrfx_pwm example for sequence loaded in common mode.");
NRFX_EXAMPLE_LOG_PROCESS();
//colour_sequence(pwm_val, 0x00, 0x00, 0xFF);
//nrfx_pwm_config_t config = NRFX_PWM_DEFAULT_CONFIG(LED1_PIN, LED2_PIN, LED3_PIN, LED4_PIN);
status = nrfx_pwm_init(&pwm_instance1, &config1, pwm_handler, &pwm_instance1);
NRFX_ASSERT(status == NRFX_SUCCESS);
k_mutex_lock(&key, K_FOREVER);
//LOG_HEXDUMP_INF(pwm_array_val, sizeof(pwm_array_val),"Thread0 Data");
/* nrfx_pwm_simple_playback(&pwm_instance, &seq_set1, PLAYBACK_COUNT, NRFX_PWM_FLAG_LOOP);
k_busy_wait(20000);*/
int i = 0;
ledupdate(0xFF, 0X00, (i%8));
k_mutex_unlock(&key);
// k_busy_wait(20000);
i++;
// at the moment set not to change as the LEDS can't update -> focus on getting ADC to work.
while (1) {
k_busy_wait(20000);
}
}
static int16_t sample;
static nrfx_saadc_channel_t channel = NRFX_SAADC_DEFAULT_CHANNEL_SE(NRF_SAADC_INPUT_AIN0, 0);
//Thread to configure ADC and to filter + convert the sensor value to a temperature.
void thread1(void)
{
uint16_t measured;
//status value for errors
/* STEP 5.1 - Connect ADC interrupt to nrfx interrupt handler */
IRQ_CONNECT(DT_IRQN(DT_NODELABEL(adc)),
DT_IRQ(DT_NODELABEL(adc), priority),
nrfx_isr, nrfx_saadc_irq_handler, 0);
/* STEP 5.2 - Connect ADC interrupt to nrfx interrupt handler */
nrfx_err_t err = nrfx_saadc_init(DT_IRQ(DT_NODELABEL(adc), priority));
if (err != NRFX_SUCCESS)
{
printk("nrfx_saadc_mode_trigger error: %08x", err);
return;
}
/* STEP 5.3 - Configure the SAADC channel */
channel.channel_config.gain = NRF_SAADC_GAIN1_6;
err = nrfx_saadc_channels_config(&channel, 1);
if (err != NRFX_SUCCESS)
{
printk("nrfx_saadc_channels_config error: %08x", err);
return;
}
/* STEP 5.4 - Configure nrfx_SAADC driver in simple and blocking mode */
err = nrfx_saadc_simple_mode_set(BIT(0),
NRF_SAADC_RESOLUTION_12BIT,
NRF_SAADC_OVERSAMPLE_DISABLED,
NULL);
if (err != NRFX_SUCCESS) {
printk("nrfx_saadc_simple_mode_set error: %08x", err);
return;
}
/* STEP 5.5 - Set buffer where sample will be stored */
err = nrfx_saadc_buffer_set(&sample, 1);
if (err != NRFX_SUCCESS) {
printk("nrfx_saadc_buffer_set error: %08x", err);
return;
}
while(1){
nrfx_err_t err = nrfx_saadc_mode_trigger();
if (err != NRFX_SUCCESS) {
printk("nrfx_saadc_mode_trigger error: %08x", err);
return;
}
k_mutex_lock(&key,K_FOREVER);
/* STEP 7.3 - Calculate and print voltage */
int voltage = ((600*6) * sample) / ((1<<12));
int temp = (voltage - 500)/19.5;
printk("SAADC sample: %d\n", sample);
printk("Voltage: %d mV\n", voltage);
k_mutex_unlock(&key);
k_msleep(500);
}
}
/**
* @brief Function for handling PWM driver events.
*
* @param[in] event_type PWM event.
* @param[in] p_context General purpose parameter set during initialization of
* the timer. This parameter can be used to pass
* additional information to the handler function.
*/
/**
* @brief Function for application main entry.
*
* @return Nothing.
*/
K_THREAD_DEFINE(thread0_id, STACKSIZE, thread0, NULL, NULL, NULL,
THREAD0_PRIORITY, 0, 0);
K_THREAD_DEFINE(thread1_id, STACKSIZE, thread1, NULL, NULL, NULL,
THREAD1_PRIORITY, 0, 0);
/*int main(void)
{
nrfx_err_t status;
(void) status;
#if defined(__ZEPHYR__)
IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_PWM_INST_GET(PWM_INST_IDX)), IRQ_PRIO_LOWEST,
NRFX_PWM_INST_HANDLER_GET(PWM_INST_IDX), 0, 0);
#endif
//NRFX_EXAMPLE_LOG_INIT();
//NRFX_LOG_INFO("Starting nrfx_pwm example for sequence loaded in common mode.");
NRFX_EXAMPLE_LOG_PROCESS();
//colour_sequence(pwm_val, 0x00, 0x00, 0xFF);
//nrfx_pwm_config_t config = NRFX_PWM_DEFAULT_CONFIG(LED1_PIN, LED2_PIN, LED3_PIN, LED4_PIN);
status = nrfx_pwm_init(&pwm_instance, &config1, pwm_handler, &pwm_instance);
NRFX_ASSERT(status == NRFX_SUCCESS);
colour_sequence(pwm_val, 0x0F, 0x00, 0x00);
ledarraybuild(pwm_array_val, 0, pwm_val);
colour_sequence(pwm_val, 0x0F, 0x00, 0x00);
ledarraybuild(pwm_array_val, 1, pwm_val);
colour_sequence(pwm_val, 0x00, 0x00, 0x00);
ledarraybuild(pwm_array_val, 2, pwm_val);
colour_sequence(pwm_val, 0x0F, 0x00, 0x00);
ledarraybuild(pwm_array_val, 3, pwm_val);
colour_sequence(pwm_val, 0x0F, 0x00, 0x00);
ledarraybuild(pwm_array_val, 4, pwm_val);
colour_sequence(pwm_val, 0x0F, 0x00, 0x00);
ledarraybuild(pwm_array_val, 5, pwm_val);
colour_sequence(pwm_val, 0x0F, 0x00, 0x00);
ledarraybuild(pwm_array_val, 6, pwm_val);
colour_sequence(pwm_val, 0x0F, 0x00, 0x00);
ledarraybuild(pwm_array_val, 7, pwm_val);
nrf_pwm_sequence_t seq_set =
{
.values = {pwm_array_val},
.length = NRFX_ARRAY_SIZE(pwm_array_val),
.repeats = VALUE_REPEATS,
.end_delay = 0
};
while (1){
k_mutex_lock(&key, K_FOREVER);
nrfx_pwm_sequence_update(&pwm_instance,0, &seq_set);
nrfx_pwm_simple_playback(&pwm_instance, &seq_set, PLAYBACK_COUNT, NRFX_PWM_FLAG_LOOP);
k_mutex_unlock(&key);
k_msleep(2000);
}
}*/
/** @} */