diff --git a/src/bus/mosfet.c b/src/bus/mosfet.c new file mode 100644 index 0000000..a5f13b2 --- /dev/null +++ b/src/bus/mosfet.c @@ -0,0 +1,35 @@ +#include "common.h" +#include "bus/mosfet.h" + +int MOS_Init(void) +{ + // PB0: MOSFET #1 Peltier + DDRB |= BIT(PB0); // Output + PORTB &= ~BIT(PB0); // Low + + // PB1: MOSFET #2 Heating + DDRB |= BIT(PB1); // Output + PORTB &= ~BIT(PB1); // Low + + // PB2: MOSFET #3 Lights + DDRB |= BIT(PB2); // Output + PORTB |= BIT(PB2); // High + + return 0; +} + +void MOS_Enable(int port) +{ + if (port != MOS01 && port != MOS02 && port != MOS03) + return; // Invalid port + + PORTB |= BIT(port); +} + +void MOS_Disable(int port) +{ + if (port != MOS01 && port != MOS02 && port != MOS03) + return; // Invalid port + + PORTB &= ~BIT(port); +} diff --git a/src/bus/mosfet.h b/src/bus/mosfet.h new file mode 100644 index 0000000..a977149 --- /dev/null +++ b/src/bus/mosfet.h @@ -0,0 +1,15 @@ +#ifndef MAD_BUS_MOSFET_H +#define MAD_BUS_MOSFET_H + +#include + +// MOSFETS +#define MOS01 PB0 // Peltier Enable +#define MOS02 PB1 // Heating Enable +#define MOS03 PB2 // Lights Enable + +int MOS_Init(void); +void MOS_Enable(int port); +void MOS_Disable(int port); + +#endif // MAD_BUS_MOSFET_H diff --git a/src/bus/pwm.c b/src/bus/pwm.c new file mode 100644 index 0000000..71fe356 --- /dev/null +++ b/src/bus/pwm.c @@ -0,0 +1,44 @@ +#include "common.h" +#include "bus/pwm.h" + +int PWM_Init(void) +{ + // PD4: PWM NF-12 Fan Peltier Hot Side + // PD5: PWM NF-A8 Fan Peltier Cold Side + // PD7: PWM NF-R8 Fan Heating Element + + DDRD |= BIT(PD4) | BIT(PD5) | BIT(PD7); + + // Fast mode, non-inverting, no prescaling + TCCR1A = BIT(WGM11) | BIT(COM1A1) | BIT(COM1B1); + TCCR1B = BIT(WGM12) | BIT(WGM13) | BIT(CS10); + TCCR2 = BIT(WGM20) | BIT(WGM21) | BIT(COM21) | BIT(CS20); + ICR1 = PWM_CYCLE_TOP; // 8000 MHz / 25000 KHz + + // TODO: Enable 25 KHz frequency for timer 3 + + OCR1A = FAN01_MIN_DUTY; + OCR1B = FAN02_MIN_DUTY; + OCR2 = FAN03_MIN_DUTY; + + return 0; +} + +// Port must be PD4, PD5 or PD7 and the value is +// expected to be in the range between 0 and 100 +void PWM_SetValue(int port, int value) +{ + int n; + + if (port != PD4 && port != PD5 && port != PD7) + return; // Invalid port + + n = CLAMP(value, 100, 0) * (PWM_CYCLE_TOP / 100.0f); + Info("Setting PWM value to %d...", n); + + switch (port) { + case PD4: OCR1B = n; break; + case PD5: OCR1A = n; break; + case PD7: OCR2 = n; break; + } +} diff --git a/src/bus/pwm.h b/src/bus/pwm.h new file mode 100644 index 0000000..959a611 --- /dev/null +++ b/src/bus/pwm.h @@ -0,0 +1,19 @@ +#ifndef MAD_BUS_PWM_H +#define MAD_BUS_PWM_H + +#include + +// PWM Devices +#define FAN01 PD4 // NF-12 Fan Peltier Hot Side Speed +#define FAN02 PD5 // NF-A8 Fan Peltier Cold Side Speed +#define FAN03 PD7 // NF-R8 Fan Heating Element Speed + +#define PWM_CYCLE_TOP (F_CPU / 25000) // 25 KHz +#define FAN01_MIN_DUTY (PWM_CYCLE_TOP * 0.2f) +#define FAN02_MIN_DUTY (PWM_CYCLE_TOP * 0.2f) +#define FAN03_MIN_DUTY (PWM_CYCLE_TOP * 0.2f) + +int PWM_Init(void); +void PWM_SetValue(int port, int value); + +#endif // MAD_BUS_PWM_H diff --git a/src/bus/twi.c b/src/bus/twi.c index 051737d..fb94790 100644 --- a/src/bus/twi.c +++ b/src/bus/twi.c @@ -105,3 +105,56 @@ int TWI_Stop(void) return 0; } + +int TWI_SetChannel(int channel) +{ + unsigned char crb; + + // assert(channel >= 0 && channel <= 3); + + // PCA9546 I2C Multiplexer + // ======================= + + Info("Switching I2C channel to %d...", channel); + + // Excerpts taken from the PCA9546A datasheet: + // https://www.ti.com/lit/ds/symlink/pca9546a.pdf + + // Following a start condition, the bus master + // must output the address of the slave it is + // accessing. + + // 7 6 5 4 | 3 2 1 0 + // 1 1 1 0 | A2 A1 A0 RW + // FIXED_____ | SELECTABLE____ + + TWI_Start(0x70, 0); + TWI_Wait_ACK(); + + // Following the successful acknowledgment of + // the slave address, the bus master sends a byte + // which is stored in the control register. + + // 7 6 5 4 | 3 2 1 0 + // X X X X | B3 B2 B1 B0 + // UNUSED____ | CHANNEL_______ + + crb = (1 << channel); + + // crb = 0x01; // Channel 0 | 00000001 + // crb = 0x02 // Channel 1 | 00000010 + // crb = 0x04 // Channel 2 | 00000100 + // crb = 0x08 // Channel 3 | 00001000 + + TWI_Write(crb); + + // When a channel is selected, the channel + // becomes active after a stop condition has been + // placed on the I2C bus. A stop condition always + // must occur right after the acknowledge cycle. + + TWI_Wait_ACK(); + TWI_Stop(); + + return 0; +} diff --git a/src/bus/twi.h b/src/bus/twi.h index f7bc15b..a43a44b 100644 --- a/src/bus/twi.h +++ b/src/bus/twi.h @@ -1,8 +1,14 @@ #ifndef MAD_CORE_BUS_TWI_H #define MAD_CORE_BUS_TWI_H +// Sensors +#define AHT01 0x0 // Upper Sensor TWI Channel +#define AHT02 0x1 // Middle Sensor TWI Channel +#define AHT03 0x2 // Lower Sensor TWI Channel + int TWI_Init(void); int TWI_Start(unsigned char addr, unsigned char mode); +int TWI_SetChannel(int channel); int TWI_Write(unsigned char data); int TWI_Wait_ACK(void); int TWI_Stop(void); diff --git a/src/common/common.c b/src/common/common.c index 132c9b5..900f49b 100644 --- a/src/common/common.c +++ b/src/common/common.c @@ -1,7 +1,6 @@ #include "common.h" #include "bus/usart.h" #include -#include static void Puts(const char *str) { diff --git a/src/main.c b/src/main.c index 09c5b1d..8d6ffb5 100644 --- a/src/main.c +++ b/src/main.c @@ -1,194 +1,40 @@ #include "common.h" #include "bus/usart.h" +#include "bus/mosfet.h" +#include "bus/pwm.h" #include "bus/twi.h" #include -// MOSFETS -#define MOS01 PB0 // Peltier Enable -#define MOS02 PB1 // Heating Enable -#define MOS03 PB2 // Lights Enable - -// PWM Devices -#define FAN01 PD4 // NF-12 Fan Peltier Hot Side Speed -#define FAN02 PD5 // NF-A8 Fan Peltier Cold Side Speed -#define FAN03 PD7 // NF-R8 Fan Heating Element Speed - -// Sensors -#define AHT01 0x0 // Upper Sensor TWI Channel -#define AHT02 0x1 // Middle Sensor TWI Channel -#define AHT03 0x2 // Lower Sensor TWI Channel - -#define PWM_CYCLE_TOP (F_CPU / 25000) // 25 KHz -#define FAN01_MIN_DUTY (PWM_CYCLE_TOP * 0.2f) -#define FAN02_MIN_DUTY (PWM_CYCLE_TOP * 0.2f) -#define FAN03_MIN_DUTY (PWM_CYCLE_TOP * 0.2f) - -static void SetPinDefaults(void); -static void SetTwiChannel(int channel); -static void SetMosState(int port, bool state); -static void SetPwmValue(int port, int value); - int main(void) { - SetPinDefaults(); - USART_Init(); - TWI_Init(); - sei(); Info("Initializing..."); - // MOS_Enable(MOS03); + MOS_Init(); + PWM_Init(); + TWI_Init(); + + MOS_Enable(MOS03); // MOS_Disable(MOS01); - // MOS_Disable(MOS02); - // PWM_Set(FAN01, 50); - // PWM_Set(FAN02, 50); - // PWM_Set(FAN03, 0); + PWM_SetValue(FAN01, 50); + PWM_SetValue(FAN02, 50); + PWM_SetValue(FAN03, 20); - SetMosState(MOS01, false); - SetMosState(MOS02, false); - SetMosState(MOS03, true); + // TODO: Set FAN03 timer frequency + // TODO: Implement ADS1115 and AHT20 - SetPwmValue(FAN01, 50); - SetPwmValue(FAN02, 50); - SetPwmValue(FAN03, 20); - - SetTwiChannel(0); // I2C Mux + TWI_SetChannel(AHT01); // I2C Mux Info("Running idle loop..."); for (;;) { - Info("PING"); + // Info("PING"); Sleep(1000); } return 0; } - -static void SetPinDefaults(void) -{ - // Initialize Pin Outputs - // ====================== - - // PB0: MOSFET #1 Peltier - - DDRB |= BIT(PB0); // Out - PORTB &= ~BIT(PB0); // Low - - // PB1: MOSFET #2 Heating - - DDRB |= BIT(PB1); // Out - PORTB &= ~BIT(PB1); // Low - - // PB2: MOSFET #3 Lights - - DDRB |= BIT(PB2); // Out - PORTB |= BIT(PB2); // High - - // PD4: PWM NF-12 Fan Peltier Hot Side - // PD5: PWM NF-A8 Fan Peltier Cold Side - // PD7: PWM NF-R8 Fan Heating Element - - DDRD |= BIT(PD4) | BIT(PD5) | BIT(PD7); - - // Fast mode, non-inverting, no prescaling - TCCR1A = BIT(WGM11) | BIT(COM1A1) | BIT(COM1B1); - TCCR1B = BIT(WGM12) | BIT(WGM13) | BIT(CS10); - TCCR2 = BIT(WGM20) | BIT(WGM21) | BIT(COM21) | BIT(CS20); - ICR1 = PWM_CYCLE_TOP; // 8000 MHz / 25000 KHz - - // TODO: Get 25 KHz frequency for timer 3 - - OCR1A = FAN01_MIN_DUTY; - OCR1B = FAN02_MIN_DUTY; - OCR2 = FAN03_MIN_DUTY; -} - -static void SetTwiChannel(int channel) -{ - unsigned char crb; - - // assert(channel >= 0 && channel <= 3); - - // PCA9546 I2C Multiplexer - // ======================= - - Info("Switching I2C channel to %d...", channel); - - // Excerpts taken from the PCA9546A datasheet: - // https://www.ti.com/lit/ds/symlink/pca9546a.pdf - - // Following a start condition, the bus master - // must output the address of the slave it is - // accessing. - - // 7 6 5 4 | 3 2 1 0 - // 1 1 1 0 | A2 A1 A0 RW - // FIXED_____ | SELECTABLE____ - - TWI_Start(0x70, 0); - TWI_Wait_ACK(); - - // Following the successful acknowledgment of - // the slave address, the bus master sends a byte - // which is stored in the control register. - - // 7 6 5 4 | 3 2 1 0 - // X X X X | B3 B2 B1 B0 - // UNUSED____ | CHANNEL_______ - - crb = (1 << channel); - - // crb = 0x01; // Channel 0 | 00000001 - // crb = 0x02 // Channel 1 | 00000010 - // crb = 0x04 // Channel 2 | 00000100 - // crb = 0x08 // Channel 3 | 00001000 - - TWI_Write(crb); - - // When a channel is selected, the channel - // becomes active after a stop condition has been - // placed on the I2C bus. A stop condition always - // must occur right after the acknowledge cycle. - - TWI_Wait_ACK(); - TWI_Stop(); - - Info("TWI channel was switched to %d!", channel); -} - -// Port must be in the range between PB0 and PB2 -static void SetMosState(int port, bool state) -{ - if (port != PB0 && port != PB1 && port != PB2) - return; // Invalid port - - Info("Setting MOS state to %s...", state ? "on" : "off"); - - if (state == true) - PORTB |= BIT(port); - else - PORTB &= ~BIT(port); -} - -// Port must be PD4, PD5 or PD7 and the value is -// expected to be in the range between 0 and 100 -static void SetPwmValue(int port, int value) -{ - int n; - - if (port != PD4 && port != PD5 && port != PD7) - return; // Invalid port - - n = CLAMP(value, 100, 0) * (PWM_CYCLE_TOP / 100.0f); - Info("Setting PWM value to %d...", n); - - switch (port) { - case PD4: OCR1B = n; break; - case PD5: OCR1A = n; break; - case PD7: OCR2 = n; break; - } -}