Skip to content

Instantly share code, notes, and snippets.

@natecostello
Last active February 8, 2020 02:08
Show Gist options
  • Save natecostello/eedfdf9f183809a81ce9e38401749f52 to your computer and use it in GitHub Desktop.
Save natecostello/eedfdf9f183809a81ce9e38401749f52 to your computer and use it in GitHub Desktop.
Example of Addressing Atmega Registers from Arduino Code
#include <Potentiometer.h>
#include <SegmentDisplay.h>
/* Runs the strobe light */
// constants related to firmware configuration
const word minFrequency = 1; //hz
const word maxFrequency = 100; //hz
const int currentOnPeriod = 200; //microseconds
//variables related to hardware inputs
float currentFrequency; //hz
float inputFrequency; //hz
int tensInput;
int onesInput;
int tenthsInput;
//variables related to interrupts
int count;
//prescale value (this must be consistent with the prescale value set
//in timer1 configuration - use a forced case later during code clean
//up)
int prescale;
//controls
Potentiometer tensPot = Potentiometer(1);
Potentiometer onesPot = Potentiometer(2);
Potentiometer tenthsPot = Potentiometer(3);
//display
SegmentDisplay segDisplay;
void setup() {
//display
segDisplay.begin(1);
//controls
tensPot.setSectors(10);
onesPot.setSectors(10);
tenthsPot.setSectors(10);
//set current frequency
currentFrequency = 1;
//initialize pin for testing (LED on 12)
pinMode(12, OUTPUT);
pinMode(13, OUTPUT);
//interrupt setup
//enabling compare timer1 A interrupt
bitSet (TIMSK1, OCIE1A);
//enabling CTC mode
bitClear (TCCR1A, WGM10);
bitClear (TCCR1B, WGM11);
bitSet (TCCR1B, WGM12);
//prescale by 256
bitClear (TCCR1B, CS10);
bitClear (TCCR1B, CS11);
bitSet (TCCR1B, CS12);
prescale = 256;
//set count corresponding to frequency
count = word(16000000/prescale/currentFrequency -1);
//need to find handle for system clock frequency
//also need to find a good rounding function
//set compare register
OCR1A = count;
//clear timer
TCNT1 = 0;
}
void loop() {
readControls();
updateDisplay();
}
//interrupt handler
ISR(TIMER1_COMPA_vect){
turnOn();
delayMicroseconds(currentOnPeriod);
turnOff();
}
void readControls(){
tensInput = tensPot.getSector();
onesInput = onesPot.getSector();
tenthsInput = tenthsPot.getSector();
inputFrequency = tensInput*10+onesInput+tenthsInput/10.0;
if (inputFrequency > maxFrequency) {
inputFrequency = maxFrequency;
}
if (inputFrequency < minFrequency) {
inputFrequency = minFrequency;
}
if (inputFrequency != currentFrequency) {
currentFrequency = inputFrequency;
updateFrequency();
}
}
void updateFrequency() {
count = word(16000000/prescale/currentFrequency - 1);
OCR1A = count;
TCNT1 = 0;
}
void turnOn(){
digitalWrite(12, HIGH);
digitalWrite(13, HIGH);
}
void turnOff(){
digitalWrite(12, LOW);
digitalWrite(13, LOW);
}
void updateDisplay(){
segDisplay.display(currentFrequency);
}
#include <Button.h>
#include <StrobeDisplay.h>
#include <Encoder.h>
/*
Runs the strobe light
Uses Timer1 - Fast PWM (mode 15) method for strobing.
Requires AuduinoMega or AtMega2560
Requires the Following Pins:
Digital Pin 12 - Strobe Signal
Digital Pin 9 - Mode Button
Digital Pin 16 - Serial 2 TX
Digital Pin 8 - Decade Button
Digital Pin 5,6,7 - Fine Encoder
Digital Pin 2,3,4 - Coarse Encoder
Has not implemented the MODE function
*/
//Debuging
const int DEBUG = 1;
//frequency bands
const int minFreqBand = 0;
const int maxFreqBand = 3;
int freqBand; //0, 1, 2, or 3
const int freqBandLow[] = {1, 5, 50, 250};
const int freqBandHigh[] = {5, 50, 250, 10000};
const int freqBandPrescale[] = {256, 64, 8, 1};
const float freqBandTick[] = {16, 4, 0.5, 0.0625}; //usec
//max and min frequency
const int freqMin = 1;
const int freqMax = 1000;
//control bands
const int minControlDec = 0;
const int maxControlDec = 4;
int controlDec; //0, 1, 2, 3, or 4
const float controlDecCoarse[] = {0.01, 0.1, 1, 10, 100};
const float controlDecFine[] = {0.001, 0.01, 0.1, 1, 10};
//flash period percentage
const int minControlFlash = 0;
const int maxControlFlash = 0;
int controlFlash; //0
const float controlFlashCoarse[] = {1};
const float controlFlashFine[] = {0.1};
const float flashPercentMin = 0.0;
const float flashPercentMax = 10.0;
//modes
int mode;
const int TRIGGER = 0;
const int DECADE = 1;
const int FLASH = 2;
const int numModes = 3;
//variables related to hardware inputs
float currentFrequency; //hz
float currentPeriod; //usec
word currentFrequencyTicks;
float inputFrequency; //hz
float inputPeriod; //usec
word inputFrequencyTicks;
int inputFrequencyDir; //1 means change was up, 0 mean change was down
float currentFlashPercent;
float currentFlashPeriod; //usec
word currentFlashTicks;
float inputFlashPercent;
float inputFlashPeriod; //usec
word inputFlashTicks;
//controls
Encoder fineEncoder;
int fineChangeFlag;
int fineDirFlag;
int fineButtonFlag;
Encoder coarseEncoder;
int coarseChangeFlag;
int coarseDirFlag;
int coarseButtonFlag;
Button decButton;
int decButtonFlag;
Button modeButton;
int modeButtonFlag;
//display
StrobeDisplay strDisplay;
void setup() {
//controls
fineEncoder.begin(6,5,7);
coarseEncoder.begin(3,2,4); //needs to be fixed
decButton.begin(8); //needs to be fixed
fineChangeFlag= 0;
fineDirFlag = 0;
fineButtonFlag = 0;
coarseChangeFlag = 0;
coarseDirFlag = 0;
coarseButtonFlag = 0;
decButtonFlag = 0;
modeButtonFlag = 0;
//control firmware
controlDec = 0;
controlFlash = 0;
freqBand = 0;
mode = DECADE;
//initialize timing variables
currentFrequency = 1.0; //hz
currentPeriod = (1/currentFrequency)*1000000.0; //usec
currentFrequencyTicks = long(inputPeriod/freqBandTick[freqBand]); //use calculateTicks
inputFrequency = currentFrequency; //hz
inputPeriod = currentPeriod; //usec
inputFrequencyTicks = currentFrequencyTicks;
currentFlashPercent = 1.0;
currentFlashPeriod = (currentFlashPercent/100.0)*currentPeriod; //usec
currentFlashTicks = long(currentFlashPeriod/freqBandTick[freqBand]); //use calculateTicks
inputFlashPercent = currentFlashPercent;
inputFlashPeriod = currentFlashPeriod; //usec
inputFlashTicks = currentFlashTicks;
//display
strDisplay.begin(2);
strDisplay.reset();
strDisplay.display(currentFrequency, controlDecCoarse[controlDec], currentFlashPercent, mode);
PWM_init(); //PWM Setup
}
void loop() {
readControls();
}
void readControls(){
fineEncoder.readEncoder(fineChangeFlag, fineDirFlag, fineButtonFlag);
coarseEncoder.readEncoder(coarseChangeFlag, coarseDirFlag, coarseButtonFlag);
decButton.readButton(decButtonFlag);
modeButton.readButton(modeButtonFlag);
//return quickly if nothing has changed
if (!fineChangeFlag & !coarseChangeFlag & !fineButtonFlag & !coarseButtonFlag & !decButtonFlag & !modeButtonFlag) return;
//update mode NOT IMPLEMENTED
if (modeButtonFlag) {
incMode();
modeButtonFlag = 0;
updateDisplay();
return;
}
//process based on mode
switch (mode) {
case TRIGGER: //not implemented
break;
case DECADE:
if (decButtonFlag) {
incControlDec();
decButtonFlag = 0;
updateDisplay();
}
if (coarseChangeFlag) {
if (coarseDirFlag) {
inputFrequency = currentFrequency + controlDecCoarse[controlDec];
inputPeriod = 1/inputFrequency*1000000.0;
inputFrequencyDir = 1;
coarseChangeFlag = 0;
coarseDirFlag = 0;
} else {
inputFrequency = currentFrequency - controlDecCoarse[controlDec];
inputPeriod = 1/inputFrequency*1000000.0;
inputFrequencyDir = 0;
coarseChangeFlag = 0;
coarseDirFlag = 0;
}
}
if (fineChangeFlag) {
if (fineDirFlag) {
inputFrequency = currentFrequency + controlDecFine[controlDec];
inputPeriod = 1/inputFrequency*1000000.0;
inputFrequencyDir = 1;
fineChangeFlag = 0;
fineDirFlag = 0;
} else {
inputFrequency = currentFrequency - controlDecFine[controlDec];
inputPeriod = 1/inputFrequency*1000000.0;
inputFrequencyDir = 0;
fineChangeFlag = 0;
fineDirFlag = 0;
}
}
if (fineButtonFlag) {
inputFrequency = currentFrequency/2.0;
inputPeriod = 1/inputFrequency*1000000.0;
fineButtonFlag = 0;
}
if (coarseButtonFlag) {
inputFrequency = currentFrequency*2.0;
inputPeriod = 1/inputFrequency*1000000.0;
coarseButtonFlag = 0;
}
updateFrequency();
updateFlashPercent();
break;
case FLASH:
if (coarseChangeFlag) {
if (coarseDirFlag) {
inputFlashPercent = currentFlashPercent + controlFlashCoarse[controlFlash];
inputFlashPeriod = (inputFlashPercent/100.0)*currentPeriod;
coarseChangeFlag = 0;
coarseDirFlag = 0;
} else {
inputFlashPercent = currentFlashPercent - controlFlashCoarse[controlFlash];
inputFlashPeriod = (inputFlashPercent/100.0)*currentPeriod;
coarseChangeFlag = 0;
coarseDirFlag = 0;
}
}
if (fineChangeFlag) {
if (fineDirFlag) {
inputFlashPercent = currentFlashPercent + controlFlashFine[controlFlash];
inputFlashPeriod = (inputFlashPercent/100.0)*currentPeriod;
fineChangeFlag = 0;
fineDirFlag = 0;
} else {
inputFlashPercent = currentFlashPercent - controlFlashFine[controlFlash];
inputFlashPeriod = (inputFlashPercent/100.0)*currentPeriod;
fineChangeFlag = 0;
fineDirFlag = 0;
}
}
if (fineButtonFlag) { //ignore control button inputs when adjusting flash percent
fineButtonFlag = 0;
}
if (coarseButtonFlag) { //ignore control button inputs when adjusting flash percent
coarseButtonFlag = 0;
}
updateFlashPercent();
break;
}
}
// Updates the global variables that contain frequency data (based on user input tracking globals):
// currentFrequency
// currentPeriod
// currentFrequncyTicks
void updateFrequency() {
if (inputFrequency == currentFrequency) return; //return if no change
if ((inputFrequency > freqMax) | (inputFrequency < freqMin)) return; //return if out of range
//shift to new frequency band if necessary
if (inputFrequency > freqBandHigh[freqBand]) raiseFreqBand();
if (inputFrequency < freqBandLow[freqBand]) lowerFreqBand();
//round to closest achievable frequency
inputFrequencyTicks = calculateTicks(inputPeriod);
//Always shift by one tick at a minimum
if (inputFrequencyTicks == currentFrequencyTicks) {
if (inputFrequencyDir) inputFrequencyTicks = inputFrequencyTicks - 1;
if (!inputFrequencyDir) inputFrequencyTicks = inputFrequencyTicks + 1;
}
inputFrequencyDir = 0;
currentFrequencyTicks = inputFrequencyTicks;
currentPeriod = calculatePeriod(currentFrequencyTicks);
currentFrequency = 1000000.0/currentPeriod;
updateTOP();
updateDisplay();
}
// Updates the global variables that contain duty cycle data (based on frequency globals or user input tracking globals)
void updateFlashPercent(){
if ((inputFlashPercent > flashPercentMax) || (inputFlashPercent < flashPercentMin)) return; //return if out of range
//round to closest achievable tickPeriod
inputFlashTicks = calculateTicks((inputFlashPercent/100.0)*currentPeriod);
currentFlashTicks = inputFlashTicks;
currentFlashPeriod = calculatePeriod(currentFlashTicks);
currentFlashPercent = (currentFlashPeriod/currentPeriod)*100.0;
updateOFF();
updateDisplay();
}
void updateDisplay(){
strDisplay.display(currentFrequency, controlDecCoarse[controlDec], currentFlashPercent, mode);
}
// Increments the frequency band and updates
// approriate control registers and bits
void raiseFreqBand(){
freqBand++;
if (freqBand > maxFreqBand) freqBand = maxFreqBand;
updateTOP();
updateOFF();
updatePrescale();
}
// Decrements the frequency band and updates
// approriate control registers and bits
void lowerFreqBand(){
freqBand--;
if (freqBand < minFreqBand) freqBand = minFreqBand;
updateTOP();
updateOFF();
updatePrescale();
}
// Calculates TOP value based on the currentFrequency
// and frequency band and writes it to the OCR1A register
void updateTOP(){
OCR1A = calculateTicks(currentPeriod);
}
// Calculates OFF value based on the currentFrequency,
// currentFlashPeriod, and frequency band
// and writes it to the OCR1B register
void updateOFF(){
OCR1B = calculateTicks(currentFlashPeriod);
}
// Sets the prescale based on the frequency band
// by setting/clearing the appropriate Clock Select bits
void updatePrescale(){
switch(freqBandPrescale[freqBand]) {
case 256: //prescale = 256
TCCR1B &= ~((1 << CS12) | (1 << CS11) | (1 << CS10)); //clear Clock Select Bits
TCCR1B |= (1 << CS12); //set Clock Select Bits
break;
case 64: //prescale = 64
TCCR1B &= ~((1 << CS12) | (1 << CS11) | (1 << CS10)); //clear Clock Select Bits
TCCR1B |= (1 << CS11) | (1 << CS10); //set Clock Select Bits
break;
case 8: //prescale = 8
TCCR1B &= ~((1 << CS12) | (1 << CS11) | (1 << CS10)); //clear Clock Select Bits
TCCR1B |= (1 << CS11); //set Clock Select Bits
break;
case 1: //prescale = 1
TCCR1B &= ~((1 << CS12) | (1 << CS11) | (1 << CS10)); //clear Clock Select Bits
TCCR1B |= (1 << CS10); //set Clock Select Bits
break;
default: //input is not a valid choice
break;
}
}
//Increments the Decade (scale) of the controls
void incControlDec(){
controlDec = (controlDec+1)%(maxControlDec+1); //increment or wrap
}
//Increments the Mode
void incMode(){
mode = (mode+1)%numModes; //increment or wrap mode
}
// Calculates the Ticks in a Time Period based on
// the current clock prescale
word calculateTicks(float us_period) {
return word(round(us_period/freqBandTick[freqBand]-1));
}
// Calculates the Period based on Ticks and
// the current clock prescale
float calculatePeriod(word ticks) {
return (ticks+1)*freqBandTick[freqBand];
}
// initializes
void PWM_init(){
//set TCCR1A and TCCR1B for Non-inverted FAST PWM with OCR1A=TOP (mode 15)
//Initially, TCCR1A = TCCR1B = x00
TCCR1A |= (1 << COM1B1) | (1 << COM1B0) | (1 << WGM11) | (1 << WGM10);
TCCR1B |= (1 << WGM13) | (1 << WGM12);
pinMode(12, OUTPUT); //set DDR for OC1B
updateTOP(); //set OCR1A (TOP)
updateOFF(); //set OCR1B (OFF)
updatePrescale(); //sets prescale and starts the clock
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment