When AB voltage is slightly above zero, i get interrupt from optocoupler. ( Red dot)
We are now at blue dot.
Now we need to start firing thyristors, first is AB pair at α = 30, next is AC pair at α = 90, and so on to the CB at α = 330
Cycle ends and is started from the beggining.
Notice that, when CB conduction is still going on, we have already interrupt, so this cant block each other.
Curcuit is regulating output voltage by delaying thyristor fire ( for now lets focus on program core, this feature can be easily added later)
In real world big thyristors need to be fired in whole time of conduction to ensure proper operation, that's why im outputting pwm instead of pulses
Code: Select all
#pragma region include libraries
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#include "esp_task_wdt.h"
#include "esp_log.h"
#include "esp_adc/adc_oneshot.h"
#include "esp_adc/adc_cali.h"
#include "esp_adc/adc_cali_scheme.h"
#include "74HC595.h"
#include "driver/gptimer.h"
#include "tm1637.h"
#include <driver/ledc.h>
#include "button_gpio.h"
#include "iot_button.h"
#include "esp_system.h"
#include "esp_timer.h"
#include <time.h>
#include "freertos/semphr.h"
#pragma endregion
#pragma region Pin Definitions
#define BUTTON1 1 //digital input
#define BUTTON2 2 //digital input
#define BUTTON3 42 //digital input
#define BUTTON4 41 //digital input
#define PhaseDetect 9 //digital input with interrupt
#define Data 4 //digital output
#define Clock 5 //digital output
#define Latch 6 //digital output
#define CLK2 38 //digital output
#define DIO1 39 //digital output
#define CLK1 40 //digital output
#define DIO2 45 //digital output
#define MotorPWM 10 //pwm output
#define TY1pin 47 //pwm output
#define TY2pin 14 //pwm output
#define TY3pin 12 //pwm output
#define TY4pin 21 //pwm output
#define TY5pin 13 //pwm output
#define TY6pin 11 //pwm output
#define HallSignal ADC_CHANNEL_5 //adc 2 analog input
#define Pot2 ADC_CHANNEL_6 //adc 1 analog input
#define Pot1 ADC_CHANNEL_4 //adc 2 analog input
#define RectifierOutput ADC_CHANNEL_6 //adc 2 analog input
#define T100 ADC_CHANNEL_7 //adc 2 analog input
#define T200 ADC_CHANNEL_7 //adc 1 analog input
#define TY_CHANNEL_1 LEDC_CHANNEL_0
#define TY_CHANNEL_2 LEDC_CHANNEL_1
#define TY_CHANNEL_3 LEDC_CHANNEL_2
#define TY_CHANNEL_4 LEDC_CHANNEL_3
#define TY_CHANNEL_5 LEDC_CHANNEL_4
#define TY_CHANNEL_6 LEDC_CHANNEL_5
#define TY_TIMER_NUM LEDC_TIMER_0
#define TY_MODE LEDC_LOW_SPEED_MODE
#define TY_DUTY_RES LEDC_TIMER_4_BIT
#define TY_FREQUENCY 10000
#define MOT_CHANNEL LEDC_CHANNEL_6
#define MOT_TIMER_NUM LEDC_TIMER_1
#define MOT_MODE LEDC_LOW_SPEED_MODE
#define MOT_DUTY_RES LEDC_TIMER_10_BIT
#define MOT_FREQUENCY 10000
#define ADC_BITWIDTH ADC_BITWIDTH_12
#define ADC_ATTEN_T ADC_ATTEN_DB_12
#define ADC_ATTEN_OTHER ADC_ATTEN_DB_0
#pragma endregion
static gptimer_handle_t timer1 = NULL;
static gptimer_handle_t timer2 = NULL;
static adc_oneshot_unit_handle_t ADC1 , ADC2;
static tm1637_handle_t display1 , display2 ;
volatile uint32_t SEQUENCE = 0;
TaskHandle_t firing_task_handle = NULL;
void IRAM_ATTR Interrupt()
{
gptimer_set_raw_count(timer1, 0);
gptimer_start(timer1);
}
bool IRAM_ATTR timer_callback(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data)
{
gptimer_stop(timer1);
gptimer_stop(timer2);
gptimer_set_raw_count(timer2, 0);
gptimer_start(timer2);
SEQUENCE = 1;
return pdFALSE;
}
static inline void TY1_SET(uint32_t duty)
{
ledc_set_duty(TY_MODE, TY_CHANNEL_1, duty);
ledc_update_duty(TY_MODE, TY_CHANNEL_1);
}
static inline void TY2_SET(uint32_t duty)
{
ledc_set_duty(TY_MODE, TY_CHANNEL_2, duty);
ledc_update_duty(TY_MODE, TY_CHANNEL_2);
}
static inline void TY3_SET(uint32_t duty)
{
ledc_set_duty(TY_MODE, TY_CHANNEL_3, duty);
ledc_update_duty(TY_MODE, TY_CHANNEL_3);
}
static inline void TY4_SET(uint32_t duty)
{
ledc_set_duty(TY_MODE, TY_CHANNEL_4, duty);
ledc_update_duty(TY_MODE, TY_CHANNEL_4);
}
static inline void TY5_SET(uint32_t duty)
{
ledc_set_duty(TY_MODE, TY_CHANNEL_5, duty);
ledc_update_duty(TY_MODE, TY_CHANNEL_5);
}
static inline void TY6_SET(uint32_t duty)
{
ledc_set_duty(TY_MODE, TY_CHANNEL_6, duty);
ledc_update_duty(TY_MODE, TY_CHANNEL_6);
}
bool IRAM_ATTR timer_callback2(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data)
{
switch (SEQUENCE)
{
case 0:
TY1_SET(0);
TY2_SET(0);
TY3_SET(0);
TY4_SET(0);
TY5_SET(0);
TY6_SET(0);
break;
case 1:
TY1_SET(8);
TY2_SET(0);
TY3_SET(0);
TY4_SET(0);
TY5_SET(0);
TY6_SET(8);
break;
case 2 :
TY1_SET(8);
TY2_SET(0);
TY3_SET(0);
TY4_SET(0);
TY5_SET(8);
TY6_SET(0);
break;
case 3:
TY1_SET(0);
TY2_SET(0);
TY3_SET(8);
TY4_SET(0);
TY5_SET(8);
TY6_SET(0);
break;
case 4 :
TY1_SET(0);
TY2_SET(0);
TY3_SET(8);
TY4_SET(8);
TY5_SET(0);
TY6_SET(0);
break;
case 5:
TY1_SET(0);
TY2_SET(8);
TY3_SET(0);
TY4_SET(8);
TY5_SET(0);
TY6_SET(0);
break;
case 6:
TY1_SET(0);
TY2_SET(8);
TY3_SET(0);
TY4_SET(0);
TY5_SET(0);
TY6_SET(8);
break;
}
SEQUENCE++;
gptimer_set_raw_count(timer2, 0);
return pdTRUE;
}
void TIMER1_CONFIG(void) {
#pragma region TIMER CONF
gptimer_config_t config = {
.clk_src = GPTIMER_CLK_SRC_DEFAULT,
.direction = GPTIMER_COUNT_UP,
.resolution_hz = 1 * 1000000,
};
gptimer_new_timer(&config, &timer1);
static gptimer_alarm_config_t alarm_config = {
.alarm_count = 1,
.reload_count = 0,
.flags.auto_reload_on_alarm = false,
};
gptimer_set_alarm_action(timer1, &alarm_config);
gptimer_register_event_callbacks(timer1, &(gptimer_event_callbacks_t){
.on_alarm = timer_callback
}, NULL);
gptimer_enable(timer1);
ESP_LOGI("TIMER1" , "TIMER 1 CONFIGURED");
#pragma endregion
}
void TIMER2_CONFIG(void) {
#pragma region TIMER CONF
gptimer_config_t config = {
.clk_src = GPTIMER_CLK_SRC_DEFAULT,
.direction = GPTIMER_COUNT_UP,
.resolution_hz = 1 * 1000000,
};
gptimer_new_timer(&config, &timer2);
static gptimer_alarm_config_t alarm_config = {
.alarm_count = 3333,
.reload_count = 0,
.flags.auto_reload_on_alarm = true,
};
gptimer_set_alarm_action(timer2, &alarm_config);
gptimer_register_event_callbacks(timer2, &(gptimer_event_callbacks_t){
.on_alarm = timer_callback2
}, NULL);
gptimer_enable(timer2);
ESP_LOGI("TIMER2" , "TIMER 2 CONFIGURED");
#pragma endregion
}
void ADC_CONFIG(void) {
adc_oneshot_unit_init_cfg_t init_config1 = {
.unit_id = ADC_UNIT_1,
.clk_src = ADC_RTC_CLK_SRC_DEFAULT,
};
adc_oneshot_new_unit(&init_config1, &ADC1);
adc_oneshot_unit_init_cfg_t init_config2 = {
.unit_id = ADC_UNIT_2,
.clk_src = ADC_RTC_CLK_SRC_DEFAULT,
};
adc_oneshot_new_unit(&init_config2, &ADC2);
adc_oneshot_chan_cfg_t config1 = {
.bitwidth = ADC_BITWIDTH,
.atten = ADC_ATTEN_OTHER,
};
adc_oneshot_config_channel(ADC2, HallSignal ,&config1);
adc_oneshot_chan_cfg_t config2 = {
.bitwidth = ADC_BITWIDTH,
.atten = ADC_ATTEN_OTHER,
};
adc_oneshot_config_channel(ADC1, Pot2 ,&config2);
adc_oneshot_chan_cfg_t config3 = {
.bitwidth = ADC_BITWIDTH,
.atten = ADC_ATTEN_OTHER,
};
adc_oneshot_config_channel(ADC2, Pot1 ,&config3);
adc_oneshot_chan_cfg_t config4 = {
.bitwidth = ADC_BITWIDTH,
.atten = ADC_ATTEN_OTHER,
};
adc_oneshot_config_channel(ADC2, RectifierOutput ,&config4);
adc_oneshot_chan_cfg_t config5 = {
.bitwidth = ADC_BITWIDTH,
.atten = ADC_ATTEN_T,
};
adc_oneshot_config_channel(ADC2, T100,&config5);
adc_oneshot_chan_cfg_t config6 = {
.bitwidth = ADC_BITWIDTH,
.atten = ADC_ATTEN_OTHER,
};
adc_oneshot_config_channel(ADC1, T200 ,&config6);
ESP_LOGI("ADC" , "ADC Configured");
// adc_oneshot_read(ADC2, HallSignal, &HALLSIGNAL_VALUE);
}
void SCREEN_CONFIG(void)
{
// SCREENS CONFIG
tm1637_config_t config10 = {
.clk_pin = CLK1,
.dio_pin = DIO1,
.bit_delay_us = 100
};
tm1637_config_t config20 = {
.clk_pin = CLK2,
.dio_pin = DIO2,
.bit_delay_us = 100
};
tm1637_init(&config10, &display1);
tm1637_init(&config20, &display2);
tm1637_set_brightness(display1, 7, true);
tm1637_set_brightness(display2, 7, true);
tm1637_show_number(display1, 0000, true, 4, 0);
tm1637_show_number(display2, 0000, true, 4, 0);
vTaskDelay(1000/ portTICK_PERIOD_MS);
tm1637_clear(display1);
tm1637_clear(display2);
ESP_LOGI("SCREENS" , "Screens Configured");
int value = 0;
tm1637_show_number(display1, value , true, 4, 0);
}
void HC595_CONFIG(void) {
// HC595 pcb output schematic
// 24V 0 1 2 3 4 5 6
// I I I I I I I
HC595_INIT();
close_led_all();
ESP_LOGI("HC595" , "HC595 Configured");
}
void IO_CONFIG(void) {
gpio_config_t BUTTON1_CONF = {
.pin_bit_mask = (1ULL << BUTTON1 ), // Select GPIO
.mode = GPIO_MODE_INPUT, // Set as output
.pull_up_en = GPIO_PULLUP_DISABLE, // Disable pull-up
.pull_down_en = GPIO_PULLDOWN_DISABLE, // Disable pull-down
.intr_type = GPIO_INTR_DISABLE // Disable interrupts
};
gpio_config_t BUTTON2_CONF = {
.pin_bit_mask = (1ULL << BUTTON2 ), // Select GPIO
.mode = GPIO_MODE_INPUT, // Set as output
.pull_up_en = GPIO_PULLUP_DISABLE, // Disable pull-up
.pull_down_en = GPIO_PULLDOWN_DISABLE, // Disable pull-down
.intr_type = GPIO_INTR_DISABLE // Disable interrupts
};
gpio_config_t BUTTON3_CONF = {
.pin_bit_mask = (1ULL << BUTTON3 ), // Select GPIO
.mode = GPIO_MODE_INPUT, // Set as output
.pull_up_en = GPIO_PULLUP_DISABLE, // Disable pull-up
.pull_down_en = GPIO_PULLDOWN_DISABLE, // Disable pull-down
.intr_type = GPIO_INTR_DISABLE // Disable interrupts
};
gpio_config_t BUTTON4_CONF = {
.pin_bit_mask = (1ULL << BUTTON4 ), // Select GPIO
.mode = GPIO_MODE_INPUT, // Set as output
.pull_up_en = GPIO_PULLUP_DISABLE, // Disable pull-up
.pull_down_en = GPIO_PULLDOWN_DISABLE, // Disable pull-down
.intr_type = GPIO_INTR_DISABLE // Disable interrupts
};
gpio_config(&BUTTON1_CONF);
gpio_config(&BUTTON2_CONF);
gpio_config(&BUTTON3_CONF);
gpio_config(&BUTTON4_CONF);
ESP_LOGI("GPIO" , "GPIO Configured");
}
void PWM_CONFIG(void) {
ledc_timer_config_t TY_TIMER = {
.speed_mode = TY_MODE,
.duty_resolution = TY_DUTY_RES,
.timer_num = TY_TIMER_NUM,
.freq_hz = TY_FREQUENCY
};
ledc_timer_config(&TY_TIMER);
ledc_channel_config_t TYconfig1 = {
.gpio_num = TY1pin,
.speed_mode = TY_MODE,
.channel = TY_CHANNEL_1,
.timer_sel = TY_TIMER_NUM,
.duty = 0
};
ledc_channel_config(&TYconfig1);
ledc_channel_config_t TYconfig2 = {
.gpio_num = TY2pin,
.speed_mode = TY_MODE,
.channel = TY_CHANNEL_2,
.timer_sel = TY_TIMER_NUM,
.duty = 0
};
ledc_channel_config(&TYconfig2);
ledc_channel_config_t TYconfig3 = {
.gpio_num = TY3pin,
.speed_mode = TY_MODE,
.channel = TY_CHANNEL_3,
.timer_sel = TY_TIMER_NUM,
.duty = 0
};
ledc_channel_config(&TYconfig3);
ledc_channel_config_t TYconfig4 = {
.gpio_num = TY4pin,
.speed_mode = TY_MODE,
.channel = TY_CHANNEL_4,
.timer_sel = TY_TIMER_NUM,
.duty = 0
};
ledc_channel_config(&TYconfig4);
ledc_channel_config_t TYconfig5 = {
.gpio_num = TY5pin,
.speed_mode = TY_MODE,
.channel = TY_CHANNEL_5,
.timer_sel = TY_TIMER_NUM,
.duty = 0
};
ledc_channel_config(&TYconfig5);
ledc_channel_config_t TYconfig6 = {
.gpio_num = TY6pin,
.speed_mode = TY_MODE,
.channel = TY_CHANNEL_6,
.timer_sel = TY_TIMER_NUM,
.duty = 0
};
ledc_channel_config(&TYconfig6);
ledc_timer_config_t MOT_TIMER = {
.speed_mode = MOT_MODE,
.duty_resolution = MOT_DUTY_RES,
.timer_num = MOT_TIMER_NUM,
.freq_hz = MOT_FREQUENCY
};
ledc_timer_config(&MOT_TIMER);
ledc_channel_config_t MOTconfig = {
.gpio_num = MotorPWM,
.speed_mode = MOT_MODE,
.channel = MOT_CHANNEL,
.timer_sel = MOT_TIMER_NUM,
.duty = 0
};
ledc_channel_config(&MOTconfig);
ESP_LOGI("PWM" , "PWM configured");
}
void ISR_CONFIG(void) {
gpio_set_direction(PhaseDetect, GPIO_MODE_INPUT);
gpio_set_pull_mode(PhaseDetect, GPIO_PULLUP_ENABLE);
gpio_set_intr_type(PhaseDetect, GPIO_INTR_POSEDGE);
gpio_install_isr_service(0);
gpio_isr_handler_add(PhaseDetect, Interrupt, NULL);
ESP_LOGI("ISR" , "ISR CONFIGURED");
}
void app_main(void)
{
TIMER1_CONFIG();
TIMER2_CONFIG();
ADC_CONFIG();
SCREEN_CONFIG();
HC595_CONFIG();
IO_CONFIG();
PWM_CONFIG();
ISR_CONFIG();
}
When measuring with oscilloscope it sometimes skips a sequence, or two, or one pulse is shorter than it should be, i can even hear this because whole thing works in audible frequency.
So i tried multiple takes to write this program, ai help, and nothing worked and i'm stuck at this.