IoT Nano 33 Timers

For a project I have to fulfill the following conditions:
1)
Setup interrupts on the ARM Cortex MCU using CMSIS APIs
a)
Show how to initialise global interrupts on the ARM Cortex for GPIO pins and timers.
b)
What are the default CMSIS ISR functions on the ARM Cortex M0+ for servicing interrupts on GPIO pins and timers?
2)
Configure a TCCx timer in interrupt mode.
a)
Write a class of methods to initialise a TCCx timer to count to a maximum period of 1 minute with a timer tick time of 1 ms.
b)
Add a method to configure and attach a GPIO pin of choice to this TCCx timer.
c)
Write any necessary start and stop methods.
d)
Initialise the NVIC and ISR to trigger on an interrupt from TCCx.

#include "sam.h"

// ---------------- LED + Button ----------------
#define NUM_LEDS 6
const uint8_t LED_PINS[NUM_LEDS] = {6, 18, 20, 21, 16, 19}; // PAxx pins
#define BUTTON_PIN 2   // PA02

// Knight Rider state
typedef enum { STOPPED, RUNNING } State;
volatile State systemState = STOPPED;
volatile int krIndex = 0;
volatile int krDir = 1;

// ---------------- TCC Timer ----------------
#define STEP_INTERVAL_MS 500   // 500ms per step
typedef struct {
    Tcc* tcc;            // Pointer to TCCx registers
    uint32_t tick_ms;    // Tick time in ms
    uint32_t max_count;  // Max count (for 1 step)
    IRQn_Type irq;       // NVIC IRQ number
} MyTCC_Timer;
MyTCC_Timer tcc1Timer;

// ----------------- LED Init -----------------
void initLEDs(void) {
    for (int i = 0; i < NUM_LEDS; i++) {
        PORT->Group[0].DIRSET.reg = (1 << LED_PINS[i]);  // output
        PORT->Group[0].OUTCLR.reg = (1 << LED_PINS[i]);  // off
    }
}

// ----------------- Button Init -----------------
void initButton(void) {
    PM->APBAMASK.reg |= PM_APBAMASK_EIC; // Enable EIC clock

    // GCLK for EIC (use GCLK3)
    GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID_EIC | GCLK_CLKCTRL_GEN_GCLK3 | GCLK_CLKCTRL_CLKEN;
    while (GCLK->STATUS.bit.SYNCBUSY);

    // Configure PA02 as input for button
    PORT->Group[0].DIRCLR.reg = (1 << BUTTON_PIN);
    PORT->Group[0].PINCFG[BUTTON_PIN].bit.PMUXEN = 1;
    PORT->Group[0].PMUX[BUTTON_PIN >> 1].bit.PMUXE = PORT_PMUX_PMUXE_A; // function A = EIC

    // Configure external interrupt for falling edge
    EIC->CONFIG[0].reg |= EIC_CONFIG_SENSE2_FALL;
    EIC->INTENSET.reg = (1 << BUTTON_PIN);

    EIC->CTRL.bit.ENABLE = 1;
    while (EIC->STATUS.bit.SYNCBUSY);

    NVIC_EnableIRQ(EIC_IRQn);
}

// ----------------- TCC Init -----------------
void TCC_Init(MyTCC_Timer* timer, Tcc* tcc_instance, uint32_t tick_ms, uint32_t step_ms, IRQn_Type irq) {
    timer->tcc = tcc_instance;
    timer->tick_ms = tick_ms;
    timer->max_count = step_ms / tick_ms;  // ticks per step
    timer->irq = irq;

    // Enable TCC1 clock
    PM->APBCMASK.bit.TCC1_ = 1;

    // Generic clock for TCC1 (GCLK3)
    GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID_TCC2_TC3 | GCLK_CLKCTRL_GEN_GCLK3 | GCLK_CLKCTRL_CLKEN;
    while (GCLK->STATUS.bit.SYNCBUSY);

    // Reset TCC
    tcc_instance->CTRLA.bit.SWRST = 1;
    while (tcc_instance->SYNCBUSY.bit.SWRST);

    // Configure prescaler, period
    tcc_instance->CTRLA.reg = TCC_CTRLA_PRESCALER_DIV1024; // 1ms tick
    tcc_instance->PER.reg = timer->max_count;
    while (tcc_instance->SYNCBUSY.bit.PER);

    // Enable overflow interrupt
    tcc_instance->INTENSET.reg = TCC_INTENSET_OVF;
    NVIC_EnableIRQ(timer->irq);
}

void TCC_Start(MyTCC_Timer* timer) {
    timer->tcc->CTRLA.bit.ENABLE = 1;
    while (timer->tcc->SYNCBUSY.bit.ENABLE);
}

void TCC_Stop(MyTCC_Timer* timer) {
    timer->tcc->CTRLA.bit.ENABLE = 0;
    while (timer->tcc->SYNCBUSY.bit.ENABLE);
}

// ----------------- Button ISR -----------------
void EIC_Handler(void) {
    static uint32_t lastPress = 0;
    uint32_t now = SysTick->VAL; // crude debounce
    if ((lastPress - now) & 0xFFFFFFF) return; // ignore bounces
    lastPress = now;

    EIC->INTFLAG.reg = (1 << BUTTON_PIN); // clear interrupt

    if (systemState == STOPPED) systemState = RUNNING;
    else if (systemState == RUNNING) systemState = STOPPED;
}

// ----------------- TCC1 ISR -----------------
void TCC1_Handler(void) {
    if (TCC1->INTFLAG.bit.OVF) {
        TCC1->INTFLAG.reg = TCC_INTFLAG_OVF; // clear flag
        if (systemState == RUNNING) {
            PORT->Group[0].OUTCLR.reg = (1 << LED_PINS[krIndex]); // turn off old LED
            krIndex += krDir;
            if (krIndex == 0 || krIndex == NUM_LEDS-1) krDir = -krDir;
            PORT->Group[0].OUTSET.reg = (1 << LED_PINS[krIndex]); // turn on new LED
        }
    }
}

// ----------------- Main -----------------
int main(void) {
    SystemInit();

    initLEDs();
    initButton();

    TCC_Init(&tcc1Timer, TCC1, 1, STEP_INTERVAL_MS, TCC1_IRQn); // 1ms tick, 500ms per step
    TCC_Start(&tcc1Timer);

    __enable_irq(); // enable global interrupts

    while (1) {
        // Main loop empty: all handled by interrupts
    }
}

When I try to upload the sketch, my board disconnects and doesnt reconnect. When I use arduino commands like millis() it works fine. I am unable to figure out the issue. Please guide me

Is that Arduino code? I don't see setup and loop.

1 Like

What course is this for?

1 Like