26.01.2019, 02:20 PM
Code:
/* A Very Basic USB/LiIon-Battery-Powered Audio Sine-Wave Test Generator
!!BUILDING SITE - MAJOR WORKS AHEAD!!
created: 2014-01-21
update: 2019-01-26
author: VoltWide
Fuse Extended Byte
7 - 1 -
6 - 1 -
5 - 1 -
4 - 1 -
3 - 1 -
2 - 1 -
1 - 1 -
0 - 1 SELFPRGEN self-programming enabled
Fuse High Byte
7 - 1 RSTDISBL ext reset disabled
6 - 1 DWEN DebugWire enabled
5 - 0 SPIEN Serial program and data download
4 - 1 WDTON watchdog timer always on
3 - 1 EESAVE EEPROM preserves chip erase
2 - 1 BODLEVEL2 Brown-out detector trigger level
1 - 1 BODLEVEL1 Brown-out detector trigger level
0 - 1 BODLEVEL0 Brown-out detector trigger level
Fuse Low Byte
7 - 0 CKDIV8 Clock divided by 8 modify 1
6 - 1 CKOUT Clock output enabled default 1
5 - 1 SUT1 Start-up slowly rising Vcc default 1
4 - 0 SUT0 Start-up slowly rising Vcc default 0
3 - 0 CKSEL3 CPU-Clock 16MHz default 0
2 - 0 CKSEL2 CPU-Clock 16MHz default 0
1 - 1 CKSEL1 CPU-Clock 16MHz modify 0
0 - 0 CKSEL0 CPU-Clock 16MHz modify 1
----------------------------------------------------------
lfuse=0xe1
DIP8/SOIC8 multilevel-pinning:
pin1 PB5 PCINT5 /RESET ADC0 dW
pin2 PB3 PCINT3 XTAL1 CLKI /OC1B ADC3
pin3 PB4 PCINT4 XTAL2 CLKO OC1B ADC2
pin4 GND
pin5 PB0 MOSI DI SDA AIN0 OC0A /OC1A AREF PCINT0
pin6 PB1 MISO DO AIN1 OC0B OC1A PCINT1
pin7 PB2 SCK USCK SCL ADC1 T0 INT0 PCINT2
pin8 VCC
*/
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/eeprom.h>
#include <avr/wdt.h>
#include <util/delay.h>
const __flash char SineTab[] = { // 8bit sinewave lookup table
0x80,0x83,0x86,0x89,0x8c,0x8f,0x92,0x95,0x98,0x9c,0x9f,0xa2,0xa5,0xa8,0xab,0xae,
0xb0,0xb3,0xb6,0xb9,0xbc,0xbf,0xc1,0xc4,0xc7,0xc9,0xcc,0xce,0xd1,0xd3,0xd5,0xd8,
0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xed,0xef,0xf0,0xf2,0xf3,0xf5,
0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfc,0xfd,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfd,0xfc,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,
0xf6,0xf5,0xf3,0xf2,0xf0,0xef,0xed,0xec,0xea,0xe8,0xe6,0xe4,0xe2,0xe0,0xde,0xdc,
0xda,0xd8,0xd5,0xd3,0xd1,0xce,0xcc,0xc9,0xc7,0xc4,0xc1,0xbf,0xbc,0xb9,0xb6,0xb3,
0xb0,0xae,0xab,0xa8,0xa5,0xa2,0x9f,0x9c,0x98,0x95,0x92,0x8f,0x8c,0x89,0x86,0x83,
0x80,0x7c,0x79,0x76,0x73,0x70,0x6d,0x6a,0x67,0x63,0x60,0x5d,0x5a,0x57,0x54,0x51,
0x4f,0x4c,0x49,0x46,0x43,0x40,0x3e,0x3b,0x38,0x36,0x33,0x31,0x2e,0x2c,0x2a,0x27,
0x25,0x23,0x21,0x1f,0x1d,0x1b,0x19,0x17,0x15,0x13,0x12,0x10,0x0f,0x0d,0x0c,0x0a,
0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x03,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x05,0x06,0x07,0x08,
0x09,0x0a,0x0c,0x0d,0x0f,0x10,0x12,0x13,0x15,0x17,0x19,0x1b,0x1d,0x1f,0x21,0x23,
0x25,0x27,0x2a,0x2c,0x2e,0x31,0x33,0x36,0x38,0x3b,0x3e,0x40,0x43,0x46,0x49,0x4c,
0x4f,0x51,0x54,0x57,0x5a,0x5d,0x60,0x63,0x67,0x6a,0x6d,0x70,0x73,0x76,0x79,0x7c
};
const __flash uint16_t FqTab[] = {2,8,32,128,512,2048,8192}; //2019-01-25: 4-16-63-250-1k-4k-16k
const int8_t FrequIdxMax = 6; //2018-12-27
// i/o mapping
#define pin1 (1<<PB5)
#define pin2 (1<<PB3)
#define pin3 (1<<PB4)
#define pin5 (1<<PB0)
#define pin6 (1<<PB1)
#define pin7 (1<<PB2)
#define OutPwmMSB pin6
#define OutLSB pin3
#define OutChargeReq pin5
#define OutPoti pin7
#define InVcc pin2
#define InPoti pin3
//input divider Rhi/Rlo=10k/2k2 Cin=0 Vref=1V1 VBattMin=3V VBattMax=4V:
//Vin(max,min) = 0.72/0.54V
//ADCin(maxs,min) =167/125
#define VBattMax 167
#define VBattHyst 5
#define EmptyBattCountDown 200
//!!! 2count/sec:
#define WDTirqCountDown 3600
//++++++++ global vars
volatile uint16_t Phase16,PhaseOfs16,WDTirqCount; // 2019-01-06
uint8_t PotiResult,VccResult,EmptyBattcount,FrequIdx; //2018-12-27
ISR(TIM1_OVF_vect) { // 2019-01-20 DDS-irq: output next sound sample
PORTB |= OutChargeReq; //!!!
Phase16 += PhaseOfs16; // 2019-01-23 16bit phase pointer
OCR1A = (SineTab[(Phase16 >> 8)]); // 2019-01-23 update pwm dutoy cycle
PORTB &= ~OutChargeReq; //!!!
}
void Boot(void){
//Timer
PLLCSR = 1<<PLLE; // 2019-01-18 start PLL: Icc=2.49mA*3V6
//wait 100us!!!
TCCR1 = (1<<PWM1A) | (1<<COM1A1) | (1<<CS11); // 2019-01-23 OC1A=MSB, PCK=64Mhz/2!!!->irq_rate=125kHz
GTCCR = (1<<TSM) | (1<<PWM1B) | (1<<COM1B1) | (1<<PSR1); // 2019-01-20 timer1: stop, OC1B=LSB, reset pre-scaler
OCR1C = -1; // 2019-01-20 max pwm cycle
TCNT1 = 0; // 2019-01-20 clear counter
OCR1A = 12; // 2019-01-20 MSB=analog zero!!!
OCR1B = 128; // 2019-01-20 LSB=analog zero
TIMSK = (1<<TOIE1); // 2019-01-20 timer1-irq on counter overflow
//Ports
MCUCR |= (1<<PUD); // 2018-12-26 pullup,sleep=off, sleepmode=idle
DDRB = OutPwmMSB | OutChargeReq | OutPoti; // 2019-01-24 output ports
PINB = -1; // 2018-12-26 power reduction of dig input buffers
DIDR0 = (1<<ADC0D) | (1<<ADC1D) | (1<<ADC2D) | (1<<ADC3D); // 2018-12-26 dig inputs=off
PORTB = OutPoti; // 2019-01-25 OutchargRequ=lo
//ADC
ADMUX = (1<<ADLAR) | (1<<MUX1); // 2019-01-26
ACSR = (1<<ACD); // 2018-12-26 comp=off
ADCSRA = 0; // 2018-12-26 ADCen,ADCstart,ADCtrig,ADCirq=off, adcclk=cpuclk/2
ADCSRB = 0; // 2018-12-26 unipolar, polarity=tru,free running
//Misc
PRR = (1<<PRTIM0) | (1<<PRUSI); // 2019-01-26 power timer0,usi=off
PhaseOfs16 = 0; // 2019-01-23
Phase16 = 0;
WDTirqCount = WDTirqCountDown; // 2019-01-06
while (!( PLLCSR & (1<<PLOCK))); // 2019-01-24 polling lock PLL
GTCCR &= ~(1<<TSM); // 2019-01-20 start counter(s)
PLLCSR = (1<<PLLE) | (1<<PCKE); // 2019-01-18 link PLL-> timer1 clk
}
void GetPoti (void) {
ADCSRA |= (1<<ADEN) | (1<<ADSC); // 2018-12-26 start ad-conversion fsample=clk/2 adcirq=off
while (0 == (ADCSRA & (1<<ADIF))); // A/D-conversion
ADCSRA |= (1<<ADIF); // 2019-01-07
PotiResult = ADCH; // bit9..2 , 8bit result
}
void GetFrequ (void) { // 2018-12-26
FrequIdx = PotiResult>>5; // 2018-12-26
if (FrequIdx>FrequIdxMax) FrequIdx=FrequIdxMax; // 2018-12-27
PhaseOfs16 = FqTab[FrequIdx]; // 2018-12-26
}
ISR(WDT_vect){ // ca 2x/s: autoclears WDIE, must be set again to avoid wdt-reset
sleep_disable(); // wakeup!
WDTirqCount--; // 2019-01-07 shutdown not here, but in main loop
WDTCR |= (1<<WDIE); // continue wdt irq, not wdt reset
}
void WDTon(void) { // 2019-01-06 p.45, safety level 1
WDTCR = (1<<WDIE) | (1<<WDE) | (1<<WDP2) | (1<<WDP0); // Watchdog timer 0.5sec ticker
MCUSR |= (1<<WDRF); // 2019-01-07 overrides WDE
}
void WDToff(void) { // 2019-01-06 p.45, safety level 1, timed sequence:
MCUSR = 0; // c.code example 8.4.2: clear WDRF
WDTCR |= (1<<WDCE) | (1<<WDE);
WDTCR = 0; // clear WDE
}
//++++++++ Main Program
int main(void) {
Boot();
sei();
for (;;) {
GetPoti();
GetFrequ();
//!!!GetVcc();
//!!!if (WDTirqCount==0) ShutDown(); // 2019-01-06
}
}
/*
changelog ******************************************************
2019-01-06b
GetVcc: UVLO shutdown removed
cpu-load minimized
2019-01-18 PLLclock -> timer1 enabled
2019-01-23 disabled: Timer0, GetVcc, sleep
sineoutput with 16bit phase offset = 256:
61/122/245/357/357Hz @clk div 16/8/4/2/1
PCK/4 works: 245*256*256*4=64MHz & PWMclk=62.7kHz with 62.5kHz measured
PCLK/2 & /1 results in PWMclkmax=125kHz
2019-01-24
fusing the attiny
AVR8-Burn-O-Mat is broken, requires JRE7, but JRE8 is installed
fusing LFuse to E1 with AVRDude immediately without data file works like this:
/usr/bin/avrdude -P usb -c usbtiny -p t25 -U lfuse:w:0xe1:m
Timer1-Clk=32MHz -> fpwm=125kHz
MCU-Clk=16MHz -> firq=125kHz
SineFreqTable: 4-16-63-250-1k-4k-16kHz
added GetPoti(), GetFrequ()
2019-01-26
bugfix: ADC-conversion stayed in endless loop: PRR had turned off ADC power!
no sleep current consumption Icc=11.2mA @3V6 &10k pots
main idle current consumption Icc=10.2mA @3V6 &10k pots
output-filter is 4.7mH 10nF
(26.01.2019, 12:46 PM)alfsch schrieb: Zeig mal dein Programm...
Ich habe die tiny85 gefunden...da kann ich dann mal mitreden, sozusagen.
...mit der Lizenz zum Löten!