I really appreciate the power of the timers in all what they can do with wave generation, pulse stuff, capture mechanics and output or event counting etc... But I feel a bit lost when I want the counter to just count to a number, generate an event, then start over. I've been at this for sometime scouring the manual and while it goes into great detail in all of the really advanced mechanics of a timer it's somewhat vague about just a very simple timer.
I'm using Atmel SAMD51J19 on an Adafruit Metro M4 board using a JTag programmer and bare metal programming. I'm trying to get TC0 (Basic Timer/Counter 0) to count up to 255 in 8-bit mode then start over and generate an event. I'm not using CMSIS and am using my own code instead.
I've selected a clock frequency of 1.768 KHz for TC0 in the GCLK and have selected it prescaled by 1024 in TC0 to just to try and get it to appear counting. The issue is it events never worked but I got it to work using interrupts however it blinks at a steady pace. I've tried changing the PRE to all different values and even the clock frequency to all different values even 120 MHz but the rate at which it blinks is steadily the same.
I don't even know what PRE is but I'm assuming from the data sheet it maybe has something to do with the reload value? Overall I'm pretty lost.
This is what I have so far, any help would be great:
/* * ENABLE EVENTS */ // Configure event channel 0 to be TC0 Overflow and to give an async output set32(EVSYS::CHANNEL::addr_32(0), EVSYS::CHANNEL::EVGEN(TC::EVGEN_TC0_OVF) | EVSYS::CHANNEL::TO_PATH_16(EVSYS::CHANNEL::PATH_ASYNCHRONOUS)); // Setup GPIO Event User 0 to be connected to channel 0 set8(EVSYS::USER::addr(GPIO::EVU_PORT_EV0_A), EVSYS::USER::CHANNEL(0)); /* * SETUP PIN A2 * A2 = LED Toggle from timer event */ // Set A2 to be out set32(GPIO::PIN::ADDR_DIR_32 + BOARD::PORT_A0, GPIO::PIN::pinToBit(BOARD::PIN_A2)); // Set A2 to be off set32(GPIO::PIN::ADDR_OUT_32 + BOARD::PORT_A0, 0); // Register pin A2 as a user to event user 0, signals will cause it to toggle set8(GPIO::EVCTRL::addr(0), GPIO::EVCTRL::PORTEIx | GPIO::EVCTRL::PIDx(BOARD::PIN_A2) | GPIO::EVCTRL::TO_EVACTx(GPIO::EVCTRL::EVACTx_TGL)); /* * ENABLE EXTERNAL INTERRUPTS * (Couldn't get events to work) */ // Enable External Interrupts set8(EIC::CTRLA::addr, EIC::CTRLA::ENABLE); // Wait until enabled while(get8(EIC::SYNCBUSY::addr) & EIC::SYNCBUSY::ENABLE > 0) continue; /* * ENABLE TIMER 0 * Timer 0 runs on a 1.768 KHz clock */ // Use in 8-bit mode and use timer clock (1.768 KHz) set32(TC::addr_tc0 + TC::CTRLA::offset1, TC::CTRLA::B1_TO_MODE(TC::CTRLA::MODE_COUNT8)); // Enable Event Output on Overflow // Doesn't work for some reason set16(TC::addr_tc0 + TC::EVCTRL::offset1, concat8to16( 0, TC::EVCTRL::B2_OVFEO )); // Enable Overflow Interrupt // Because event output doesn't work set8(TC::addr_tc0 + TC::INTEN::offsetSet, TC::INTEN::OVF); // Enable Running in Debug set8(TC::addr_tc0 + TC::DBGCTRL::offset, TC::DBGCTRL::DBGRUN); // Set Per Register set8(TC::addr_tc0 + TC::PER::offset_8, TC::PER::PER(0)); while(get8(TC::addr_tc0 + TC::SYNCBUSY::offset) & TC::SYNCBUSY::PER) continue; // Enable and scale down clock set32(TC::addr_tc0 + TC::CTRLA::offset1, concat8to32( TC::CTRLA::B1_ENABLE, TC::CTRLA::B2_PRESCALER(TC::CTRLA::PRESC_GCLK_DIV1024) )); while(get8(TC::addr_tc0 + TC::SYNCBUSY::offset) & TC::SYNCBUSY::ENABLE) continue; // Start timer set8(TC::addr_tc0 + TC::CTRLB::offsetSet, TC::CTRLB::TO_CMD(TC::CTRLB::CMD_RETRIGGER)); while(get8(TC::addr_tc0 + TC::SYNCBUSY::offset) & TC::SYNCBUSY::CTRLB) continue; /* * ENABLE MASTER INTERRUPTS */ // Enable TC0 Overflow Interupt set8(SCS::NVIC::addrISER + SCS::NVIC::findIxRByte(TC::INT_TC0_OVF), SCS::NVIC::findIxRBitFlag(TC::INT_TC0_OVF)); ///////////////////////////////////////// extern "C" __attribute__ ((interrupt)) void TC0_Handler() { // Toggle A2 set32(GPIO::PIN::ADDR_OUTTGL_32 + BOARD::PORT_A2, GPIO::PIN::pinToBit(BOARD::PIN_A2)); // Clear Overflow Interrupt set8(TC::addr_tc0 + TC::INTEN::offsetFlag, TC::INTEN::OVF); }