Go Down

Topic: Interrupt and DAC outputs (Read 225 times) previous topic - next topic

birdm3n

Hi guys! I'm using an adafruit mcp4725 DAC and what I'm trying to achieve is the possibility to output an analogic value every time a clock interrupt occurs. The problem is that it is not working. The code I'm using is this one:
Code: [Select]

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_MCP4725.h>

// Output 25kHz single slope PWM with timer TCC0 on D7
int i = 0;

Adafruit_MCP4725 dac;

#define DAC_RESOLUTION (10)

int sintable[256] PROGMEM = {
    512,524,537,549,562,574,587,599,611,624,636,648,660,672,684,696,707,719,730,741,753,764,774,785,796,806,816,826,836,846,855,864,873,882,890,899,907,915,922,930,
937,944,950,957,963,968,974,979,984,989,993,997,1001,1004,1008,1011,1013,1015,1017,1019,1021,1022,1022,1023,1023,1023,1022,1022,1021,1019,1017,1015,1013,1011,1008,1004,1001,997,993,989,
984,979,974,968,963,957,950,944,937,930,922,915,907,899,890,882,873,864,855,846,836,826,816,806,796,785,774,764,753,741,730,719,707,696,684,672,660,648,636,624,
611,599,587,574,562,549,537,524,512,499,486,474,461,449,436,424,412,399,387,375,363,351,339,327,316,304,293,282,270,259,249,238,227,217,207,197,187,177,168,159,
150,141,133,124,116,108,101,93,86,79,73,66,60,55,49,44,39,34,30,26,22,19,15,12,10,8,6,4,2,1,1,0,0,0,1,1,2,4,6,8,
10,12,15,19,22,26,30,34,39,44,49,55,60,66,73,79,86,93,101,108,116,124,133,141,150,159,168,177,187,197,207,217,227,238,249,259,270,282,293,304,
316,327,339,351,363,375,387,399,412,424,436,449,461,474,486,499
};


void setup()
{
  Serial.begin(9600); 
  dac.begin(0x62);
 
  Serial.println("MCP4725A found!");
   
  //analogWriteResolution(10);
  REG_GCLK_GENDIV = GCLK_GENDIV_DIV(1) |          // Divide the 48MHz clock source by divisor 1: 48MHz/1=48MHz
                    GCLK_GENDIV_ID(4);            // Select Generic Clock (GCLK) 4
  while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization

  REG_GCLK_GENCTRL = GCLK_GENCTRL_IDC |           // Set the duty cycle to 50/50 HIGH/LOW
                     GCLK_GENCTRL_GENEN |         // Enable GCLK4
                     GCLK_GENCTRL_SRC_DFLL48M |   // Set the 48MHz clock source
                     GCLK_GENCTRL_ID(4);          // Select GCLK4
  while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization

  // Feed GCLK4 to TCC0 and TCC1
  REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN |         // Enable GCLK4 to TCC0 and TCC1
                     GCLK_CLKCTRL_GEN_GCLK4 |     // Select GCLK4
                     GCLK_CLKCTRL_ID_TCC0_TCC1;   // Feed GCLK4 to TCC0 and TCC1
  while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization

  // Normal (single slope) PWM operation: timers countinuously count up to PER register value and then is reset to 0
  REG_TCC0_WAVE |= TCC_WAVE_WAVEGEN_NPWM;         // Setup single slope PWM on TCC0
  while (TCC0->SYNCBUSY.bit.WAVE);                // Wait for synchronization

  // Each timer counts up to a maximum or TOP value set by the PER register,
  // this determines the frequency of the PWM operation:
  REG_TCC0_PER = 1919;                            // Set the frequency of the PWM on TCC0 to 25kHz
  while(TCC0->SYNCBUSY.bit.PER);                  // Wait for synchronization
 
  // Set the PWM signal to output 50% duty cycle on D7
  REG_TCC0_CCB3 = 959;                            // TCC0 CCB3 - on output on D7 50% duty cycle
  while(TCC0->SYNCBUSY.bit.CCB3);                 // Wait for synchronization

  NVIC_SetPriority(TCC0_IRQn, 0);    // Set the Nested Vector Interrupt Controller (NVIC) priority for TCC0 to 0 (highest)
  NVIC_EnableIRQ(TCC0_IRQn);         // Connect TCC0 to Nested Vector Interrupt Controller (NVIC)

  REG_TCC0_INTENSET = TC_INTENSET_OVF;            // Enable TCC0 overflow interrupt

  // Divide the 48MHz signal by 1 giving 48MHz (20.83ns) TCC0 timer tick and enable the outputs
  REG_TCC0_CTRLA |= TCC_CTRLA_PRESCALER_DIV1 |    // Divide GCLK4 by 1
                    TCC_CTRLA_ENABLE;             // Enable the TCC0 output
  while (TCC0->SYNCBUSY.bit.ENABLE);              // Wait for synchronization

}

void loop() {}


// Interrupt handler called every time the TCC0 timer overflows
void TCC0_Handler()                              // Interrupt Service Routine (ISR) for timer TCC0
{
  // Check for overflow (OVF) interrupt
  if (TCC0->INTFLAG.bit.OVF && TCC0->INTENSET.bit.OVF)             
  {
    // Put your timer overflow (OVF) code here:     
    // ...
    //analogWrite(A0,sintable[i]);
    dac.setVoltage(pgm_read_word(&(sintable[i])), false);
    i++;
    if(i==256)
      i=0;   
    REG_TCC0_INTFLAG = TC_INTFLAG_OVF;         // Clear the OVF interrupt flag
  }
}


Why does it not work in your opinion? Thanks!

pylon

All global variables used in an interrupt service routine have to be declared "volatile", otherwise the compiler might optimize them away (code is never reached, so don't make any machine instructions for it).

birdm3n

I changed all the variables to volatile but it does not work. I found that it is possible to use a flag variable changed in the interrupt and checked in the loop in order to output the desired value. The problem is that I don't know how to increase the clock frequency of the i2c from 100kHz to 400kHz or 800kHz using an arduino m0 pro. Have you got some suggestions?

pylon

I am not sure if the I2C bus works inside an ISR on the M0.

Quote
The problem is that I don't know how to increase the clock frequency of the i2c from 100kHz to 400kHz or 800kHz using an arduino m0 pro.
Use Wire.setClock(baudrate).

Go Up