Skip to content

Commit

Permalink
Add a few examples...
Browse files Browse the repository at this point in the history
  • Loading branch information
SpenceKonde committed Apr 5, 2020
1 parent 229a6b8 commit 6b78984
Show file tree
Hide file tree
Showing 8 changed files with 224 additions and 0 deletions.
1 change: 1 addition & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* Fix bug with Wire introduced by not testing 1.1.9 changes to Wire.
* Fix bug with EEPROM introduced by not testing 1.1.9 changes to EEPROM
* Add ability to read from temp sensor, internal reference via ADC, clean up analogReference()
* Add some example sketches, including reading temp and Vcc

1.1.9
* Correct micros() results at 20, 10, and 5 MHz when TCA0 or TCD0 is used as millis source
Expand Down
27 changes: 27 additions & 0 deletions megaavr/libraries/megaTinyCore/examples/TCA0Demo/TCA0Demo.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#if defined(MILLIS_USE_TIMERA0)||defined(__AVR_ATtinyxy2__)
#error "This sketch takes over TCA0, don't use for millis here. Pin mappings on 8-pin parts are different"
#endif

unsigned int DutyCycle=0;

void setup() {
// We will be outputting PWM on PB0
pinMode(PIN_PB0, OUTPUT); //PB0 - TCA0 WO0, pin7 on 14-pin parts
TCA0.SPLIT.CTRLA=0; //disable TCA0 and set divider to 1
TCA0.SPLIT.CTRLESET=TCA_SPLIT_CMD_RESET_gc|0x03; //set CMD to RESET, and enable on both pins.
TCA0.SPLIT.CTRLD=0; //Split mode now off, CMPn = 0, CNT = 0, PER = 255
TCA0.SINGLE.CTRLB=(TCA_SINGLE_CMP0EN_bm|TCA_SINGLE_WGMODE_DSBOTTOM_gc); //Dual slope PWM mode OVF interrupt at BOTTOM, PWM on WO0
TCA0.SINGLE.PER=0xFFFF; // Count all the way up to 0xFFFF
// At 20MHz, this gives ~152Hz PWM
TCA0.SINGLE.CMP0=DutyCycle;
TCA0.SINGLE.INTCTRL=TCA_SINGLE_OVF_bm; //enable overflow interrupt
TCA0.SINGLE.CTRLA=TCA_SINGLE_ENABLE_bm; //enable the timer with no prescaler
}

void loop() { // Not even going to do anything in here
}

ISR(TCA0_OVF_vect) { //on overflow, we will increment TCA0.CMP0, this will happen after every full cycle - a little over 7 minutes.
TCA0.SINGLE.CMP0=DutyCycle++; // Because we are in Dual Slope Bottom mode, OVF fires at BOTTOM, at end, not TOP, in middle of the pulse.
TCA0.SINGLE.INTFLAGS=TCA_SINGLE_OVF_bm; //Always remember to clear the interrupt flags, otherwise the interrupt will fire continually!
}
54 changes: 54 additions & 0 deletions megaavr/libraries/megaTinyCore/examples/TCA0Demo2/TCA0Demo2.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#if defined(MILLIS_USE_TIMERA0)||defined(__AVR_ATtinyxy2__)
#error "This sketch takes over TCA0, don't use for millis here. Pin mappings on 8-pin parts are different"
#endif

unsigned int Period=0xFFFF;

void setup() {
// We will be outputting PWM on PB0
pinMode(PIN_PB0, OUTPUT); //PB0 - TCA0 WO0, pin7 on 14-pin parts
TCA0.SPLIT.CTRLA=0; //disable TCA0 and set divider to 1
TCA0.SPLIT.CTRLESET=TCA_SPLIT_CMD_RESET_gc|0x03; //set CMD to RESET, and enable on both pins.
TCA0.SPLIT.CTRLD=0; //Split mode now off, CMPn = 0, CNT = 0, PER = 255
TCA0.SINGLE.CTRLB=(TCA_SINGLE_CMP0EN_bm|TCA_SINGLE_WGMODE_SINGLESLOPE_gc); //Single slope PWM mode, PWM on WO0
TCA0.SINGLE.PER=Period; // Count all the way up to 0xFFFF
// At 20MHz, this gives ~305Hz PWM
TCA0.SINGLE.CMP0=0;
TCA0.SINGLE.CTRLA=TCA_SINGLE_ENABLE_bm; //enable the timer with no prescaler
}

void loop() { // Not even going to do anything in here
PWMDemo(150000);//150kHz
PWMDemo(70000);//70kHz
PWMDemo(15000);//15kHz
PWMDemo(3000);//3kHz
PWMDemo(120);//120Hz
PWMDemo(35);//35Hz
PWMDemo(13);//13Hz
}

void PWMDemo(unsigned long frequency){
setFrequency(frequency);
setDutyCycle(64); //~25%
delay(4000);
setDutyCycle(128); //~50%
delay(4000);
setDutyCycle(192); //~75%
delay(4000);
}

void setDutyCycle(byte duty) {
TCA0.SINGLE.CMP0=map(duty,0,255,0,Period);
}

void setFrequency(unsigned long freqInHz) {
unsigned long tempperiod=(F_CPU/freqInHz);
byte presc=0;
while (tempperiod>65536 && presc<7) {
presc++;
tempperiod=tempperiod>>(presc>4?2:1);
}
Period=tempperiod;
TCA0.SINGLE.CTRLA=(presc<<1)|TCA_SINGLE_ENABLE_bm;
TCA0.SINGLE.PER=Period;
}
42 changes: 42 additions & 0 deletions megaavr/libraries/megaTinyCore/examples/TCA0Demo3/TCA0Demo3.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#if defined(MILLIS_USE_TIMERA0)||!defined(__AVR_ATtinyxy2__)
#error "This sketch is for an 8-pin part and takes over TCA0"
#endif


void setup() {
// We will be outputting PWM on PA3 on an 8-pin part
pinMode(PIN_PA3, OUTPUT); //PA3 - TCA0 WO0, pin 4 on 8-pin parts
PORTMUX.CTRLC=PORTMUX_TCA00_DEFAULT_gc; //turn off PORTMUX, returning WO0 to PA3
TCA0.SPLIT.CTRLA = 0; //disable TCA0 and set divider to 1
TCA0.SPLIT.CTRLESET=TCA_SPLIT_CMD_RESET_gc|0x03; //set CMD to RESET, and enable on both pins.
TCA0.SPLIT.CTRLD=0; //Split mode now off, CMPn = 0, CNT = 0, PER = 255
TCA0.SINGLE.CTRLB = (TCA_SINGLE_CMP0EN_bm | TCA_SINGLE_WGMODE_SINGLESLOPE_gc); //Single slope PWM mode, PWM on WO0
TCA0.SINGLE.PER = 0x00FF; // Count all the way up to 0x00FF (255) - 8-bit PWM
// At 20MHz, this gives ~78.125kHz PWM
TCA0.SINGLE.CMP0 = 0;
TCA0.SINGLE.CTRLA = TCA_SINGLE_ENABLE_bm; //enable the timer with no prescaler
}

void loop() { //Lets generate some output just to proove it works
static byte pass = 0;
static unsigned int duty = 255;
TCA0.SINGLE.CMP0 = duty-- ; //step down the duty cycle each iteration through loop;
delay(100); //so we can see the duty cycle changing over time on the scope/with an LED
if (!duty) {
if (pass == 0) {
// After the first pass, lets go up to 100kHz
pass = 1;
duty = 199;
TCA0.SINGLE.PER = 199;
} else if (pass==1) {
//and now the requested 62 kHz (actually 62.11kHz)
pass=2;
duty = 322;
TCA0.SINGLE.PER = 322;
} else { // and back to the beginning.
pass = 0;
duty = 255;
TCA0.SINGLE.PER = 255;
}
}
}
18 changes: 18 additions & 0 deletions megaavr/libraries/megaTinyCore/examples/TCA0Demo4/TCA0Demo4.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#if defined(MILLIS_USE_TIMERA0)||defined(__AVR_ATtinyxy2__)
#error "This sketch takes over TCA0, don't use for millis here. Pin mappings on 8-pin parts are different"
#endif


void setup() {
// We will be outputting PWM on PB0 amd PA5
pinMode(PIN_PB0, OUTPUT); //PB0 - TCA0 WO0, pin7 on 14-pin parts
pinMode(PIN_PA5, OUTPUT); //PA5 - TCA0 WO5, pin1 on 14-pin parts
TCA0.SPLIT.CTRLB=TCA_SPLIT_LCMP0EN_bm|TCA_SPLIT_HCMP2EN_bm; //PWM on WO5, WO0
TCA0.SPLIT.LPER=0xFF; // Count all the way down from 255 on WO0/WO1/WO2
TCA0.SPLIT.HPER=200; // Count down from only 200 on WO3/WO4/WO5
TCA0.SPLIT.LCMP0=0x7F; //50% duty cycle
TCA0.SPLIT.HCMP2=150; //75% duty cycle
TCA0.SPLIT.CTRLA=TCA_SPLIT_CLKSEL_DIV16_gc|TCA_SPLIT_ENABLE_bm; //enable the timer with prescaler of 16
}
void loop() { //nothing to do here but enjoy your PWM. Prescaler of 16 and LPER and HPER values give 4.88 kHz on PB0 and 6.25kHz on PA5.
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/* Minimal demo of uaing the ADC to read temperature and operating voltage */

#define RESULTCOUNT 4
int16_t results[RESULTCOUNT];
int32_t sum;
int16_t average;

void setup() {
// put your setup code here, to run once:
delay(1000);
Serial.begin(57600);
}

uint16_t readSupplyVoltage() { //returns value in millivolts to avoid floating point
analogReference(VDD);
VREF.CTRLA=VREF_ADC0REFSEL_1V5_gc;
uint16_t reading = analogRead(ADC_INTREF);
uint32_t intermediate=1023*1500;
reading=intermediate/reading;
return reading;
}
void printRegisters(){
Serial.print("ADC0.MUXPOS: ");
showHex(ADC0.MUXPOS);
Serial.print(" ADC0.CTRLC: ");
showHex(ADC0.CTRLC);
Serial.print(" VREF.CTRLA: ");
showHex(VREF.CTRLA);
Serial.println();
}

uint16_t readTemp() {
//based on the datasheet, in section 30.3.2.5 Temperature Measurement
int8_t sigrow_offset = SIGROW.TEMPSENSE1; // Read signed value from signature row
uint8_t sigrow_gain = SIGROW.TEMPSENSE0; // Read unsigned value from signature row
analogReference(INTERNAL1V1);
ADC0.SAMPCTRL=0x1F; //Appears very necessary!
ADC0.CTRLD|=ADC_INITDLY_DLY32_gc; //Doesn't seem so necessary?
uint16_t adc_reading = analogRead(ADC_TEMPERATURE); // ADC conversion result with 1.1 V internal reference
Serial.println(adc_reading);
analogReference(VDD);
ADC0.SAMPCTRL=0x0;
ADC0.CTRLD&=~(ADC_INITDLY_gm);
uint32_t temp = adc_reading - sigrow_offset;
Serial.println(temp);
temp *= sigrow_gain; // Result might overflow 16 bit variable (10bit+8bit)
Serial.println(temp);
temp += 0x80; // Add 1/2 to get correct rounding on division below
temp >>= 8; // Divide result to get Kelvin
return temp;
}

void showHex (const byte b) {
char buf [3] = { ((b >> 4) & 0x0F) | '0', (b & 0x0F) | '0', 0};
if (buf [0] > '9')
buf [0] += 7;
if (buf [1] > '9')
buf [1] += 7;
Serial.print(buf);
}
void loop() {
int16_t reading=readSupplyVoltage();
Serial.print("System voltage is: ");
Serial.print(reading);
Serial.println(" mV");
reading=readTemp();
Serial.print("System temperature is: ");
Serial.print(reading);
Serial.println(" K");

delay(10000);
}
9 changes: 9 additions & 0 deletions megaavr/libraries/megaTinyCore/library.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name=ATTinyCore

This comment has been minimized.

Copy link
@MCUdude

MCUdude Apr 6, 2020

Contributor

Shouldn't the name be megaTinyCore?

This comment has been minimized.

Copy link
@SpenceKonde

SpenceKonde Apr 6, 2020

Author Owner

Yes, yes it should.... lol....

version=1.1.10
author=Spence Konde
maintainer=Spence Konde <[email protected]>
sentence=Examples of using megaTinyCore. There is no actual library - this is a workaround.
paragraph=
category=Other
url=https://github.com/SpenceKonde/megaTinyCore
architectures=avr
1 change: 1 addition & 0 deletions megaavr/libraries/megaTinyCore/src/megaTinyCore.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
//Dummy file to convince the IDE to show the examples

0 comments on commit 6b78984

Please sign in to comment.