/***********************************************************************
(c) JA 2023
remarks:
based on http://tahmidmc.blogspot.com/2013/02/sine-wave-generation-with-fast-pwm-mode_2525.html
also read http://tahmidmc.blogspot.com/2013/02/demystifying-use-of-table-pointer-in.html
adapted to atmega328, original written by Tahmid for the atmega16
array has 160 elements, why?
1/16000000 * 1000 = 0,0000625
0,0000625 * 160 = 10 ms
can not be fully tested in Tinkercad because fast PWM mode does not simulate.
last mod.: 16/05/2023
***********************************************************************/
/*
const unsigned int sin_table[32] =
{0, 100, 199, 296, 390, 480, 566, 645, 718,
783, 840, 889, 928, 958, 979, 989, 989, 979, 958, 928, 889, 840, 783,
718, 645, 566, 480, 390, 296, 199, 100, 0};
*/
/*
const unsigned int sin_table[64] =
{0, 50, 99, 149, 198, 247, 294, 342, 388, 433,
478, 521, 563, 603, 642, 679, 715, 749, 781,
811, 839, 865, 889, 911, 930, 947, 962, 974,
984, 991, 996, 999, 999, 996, 991, 984, 974,
962, 947, 930, 911, 889, 865, 839, 811, 781,
749, 715, 679, 642, 603, 563, 521, 478, 433,
388, 342, 294, 247, 198, 149, 99, 50, 0};
*/
const unsigned int sin_table[160] =
{0, 20, 39, 59, 79, 99, 118, 138, 157, 177, 196,
215, 235, 254, 273, 292, 311, 329, 348, 366, 385,
403, 421, 439, 456, 474, 491, 508, 525, 542, 558,
574, 590, 606, 622, 637, 652, 667, 682, 696, 710,
724, 737, 750, 763, 776, 788, 800, 812, 823, 834,
845, 855, 865, 875, 884, 893, 902, 910, 918, 926,
933, 940, 946, 953, 958, 964, 969, 973, 978, 981,
985, 988, 991, 993, 995, 997, 998, 998, 999, 999,
998, 998, 997, 995, 993, 991, 988, 985, 981, 978,
973, 969, 964, 958, 953, 946, 940, 933, 926, 918,
910, 902, 893, 884, 875, 865, 855, 845, 834, 823,
812, 800, 788, 776, 763, 750, 737, 724, 710, 696,
682, 667, 652, 637, 622, 606, 590, 574, 558, 542,
525, 508, 491, 474, 456, 439, 421, 403, 385, 366,
348, 329, 311, 292, 273, 254, 235, 215, 196, 177,
157, 138, 118, 99, 79, 59, 39, 20, 1};
#define FETA PB0 //PB0 = UNO D8
#define FETB PB3 //PB3 = UNO D11
#define FETC PB4 //PB4 = UNO D12
#define FETD PB5 //PB5 = UNO D13
bool Direction;
//0 -> MOS A + D
//1 -> MOS B + C
//unsigned int TBL_POINTER_NEW, TBL_POINTER_OLD, TBL_POINTER_SHIFT, SET_FREQ;
unsigned char DUTY_CYCLE;
ISR(TIMER1_OVF_vect) //updated every 62.5us (= 1/16MHz * 1 + 999 timer counts -> value in ICR)
{
DUTY_CYCLE++;
if (DUTY_CYCLE > 159)
{
if (Direction == 0)
{
//MOSA = 0;
//MOSD = 0;
PORTB &= 0b11011110; //~(1<<FETA); //MOSA
//bitClear(PORTB, FETA);
//PORTB &= 0b11011111; //~(1<<FETD); //MOSD
//bitClear(PORTB, FETD);
Direction = 1; //change here to create a deadtime
//MOSB = 1;
//MOSC = 1;
//PORTB |= 0b00001000; //(1<<FETB); //MOSB
bitSet(PORTB, FETB);
//PORTB |= 0b00010000; //(1<<FETC); //MOSC
bitSet(PORTB, FETC);
}
else
{
//MOSB = 0;
//MOSC = 0;
PORTB &= 0b11100111; //~(1<<FETB); //MOSB
//bitClear(PORTB, FETB);
//PORTB &= 0b11101111; //~(1<<FETC); //MOSC
//bitClear(PORTB, FETC);
Direction = 0; //change here to create a deadtime
//MOSA = 1;
//MOSD = 1;
//PORTB |= 0b00000001; //(1<<FETA); //MOSA
bitSet(PORTB, FETA);
//PORTB |= 0b00100000; //(1<<FETD); //MOSD
bitSet(PORTB, FETD);
}
DUTY_CYCLE = 0;
}
OCR1A = sin_table[DUTY_CYCLE];
}
int main(void)
{
asm volatile ("nop");
pinMode(FETA, OUTPUT);
digitalWrite(FETA, LOW); //MOSA = PB0, make sure upper FET A is off
pinMode(FETC, OUTPUT);
digitalWrite(FETC, LOW); //MOSC = PB4, make sure upper FET C is off
pinMode(FETB, OUTPUT);
digitalWrite(FETB, HIGH); //MOSB = PB3, turn on lower FET B
pinMode(FETD, OUTPUT);
digitalWrite(FETD, HIGH); //MOSD = PB5, turn on lower FET D
pinMode(9, OUTPUT);
//digitalWrite(9, HIGH); //turn on OC1A (PB1) output, now both lower FETS (B+D) must be on giving 0A over the load
digitalWrite(9, LOW);
//DDRC = 0xFF;
//DDRD = 0XFF;
//SET_FREQ = 410;
//TBL_POINTER_SHIFT = 0;
//TBL_POINTER_NEW = 0;
//TBL_POINTER_OLD = 0;
DUTY_CYCLE = 0;
asm volatile ("nop");
//OCR1AH = 0;
//OCR1AL = 0;
OCR1A = sin_table[DUTY_CYCLE];
TCCR1A = 0;
TCCR1B = 0;
//TCCR1A = 0x82; //mega16, 0b10000010
//mode 14 fast PWM (xxxxxx10+), (xx0000xxx), Clear OC1A on Compare Match (Set output to low level) (10xxxxxx)
TCCR1A |= (1<<COM1A1);
TCCR1A |= (1<<WGM11); //Fast PWM, ICR1 TOP
//TCCR1B = 0x19; //mega16, 0b00011001
TCCR1B |= (1<<WGM12); //Fast PWM, ICR1 TOP
TCCR1B |= (1<<WGM13); //Fast PWM, ICR1 TOP
asm volatile ("nop");
//ICR1H = 0x03;
//ICR1L = 0xE7;
ICR1 = 999; //TOP -> 16kHz
asm volatile ("nop");
//TIMSK = 0x04; //mega16
TIMSK1 = 0x01; //mega328, set TOIE1: Timer/Counter1, Overflow Interrupt Enable
asm volatile ("nop");
TCCR1B |= (1<<CS10); //Start TC1, CLKio/1
sei(); //SREG_I_bit = 1;
while(1);
{
asm volatile ("nop");
}
return 1;
}