Compare commits

...

10 Commits

Author SHA1 Message Date
9b2e729683 Merge remote-tracking branch 'origin/combine-all' 2024-05-03 19:45:53 +02:00
Sebastian H. Gabrielli
25d27c1e1b Add alarm code 2024-04-30 16:43:07 +02:00
Sebastian H. Gabrielli
cd65b8fd1f Lots of bug fixes, everything works 2024-04-30 16:17:52 +02:00
Sebastian H. Gabrielli
bc9e3f6885 Update the sample rate when the config is changed 2024-04-30 12:00:29 +02:00
Sebastian H. Gabrielli
d215e204d4 Rename files & re-factor to pretty up project 2024-04-30 11:37:21 +02:00
Sebastian H. Gabrielli
458ae00f24 Rename fanspeeeed to fanspeed 2024-04-30 11:26:08 +02:00
Sebastian H. Gabrielli
b858d29ce8 Make read bulk fan speed read correctly from the array 2024-04-30 11:21:26 +02:00
Sebastian H. Gabrielli
1671476f41 Move index incrementation over storage
This avoids the problem where the current index has outdated data.
It does however mean the first piece of stored data is empty, but it is
a worthwile tradeoff.
2024-04-30 11:11:32 +02:00
Sebastian H. Gabrielli
bcd631001b Current fan speed now returns the last fan speed measured 2024-04-30 11:10:26 +02:00
Sebastian H. Gabrielli
dd53b4dbf2 Fan data is now saved in the array
Closes #9
2024-04-30 11:08:03 +02:00
10 changed files with 151 additions and 50 deletions

View File

@ -1,4 +1,5 @@
#include "command-handler.h" #include "command-handler.h"
#include "fan-speed.h"
// Initialize empty, global command context // Initialize empty, global command context
volatile command_context_t context = {UNKNOWN_COMMAND, SRC_NONE, FAN_NONE, volatile command_context_t context = {UNKNOWN_COMMAND, SRC_NONE, FAN_NONE,
@ -126,7 +127,7 @@ void parse_command(uint8_t command[], uint8_t command_len) {
} }
// Store the parameter // Store the parameter
param = command[2]; param = command[1];
context.conf = param; context.conf = param;
@ -148,8 +149,8 @@ void parse_command(uint8_t command[], uint8_t command_len) {
uint8_t bytes[2]; uint8_t bytes[2];
} config_value; } config_value;
config_value.bytes[0] = command[3]; config_value.bytes[0] = command[2];
config_value.bytes[1] = command[4]; config_value.bytes[1] = command[3];
// Store the value // Store the value
context.conf_val = config_value.value; context.conf_val = config_value.value;
@ -168,6 +169,10 @@ uint8_t route_command(int pos) {
// Set the flag to store it in the EEPROM // Set the flag to store it in the EEPROM
store_config = true; store_config = true;
return 0;
break;
case CNF_NONE:
return 0;
break; break;
} }
break; break;
@ -197,6 +202,9 @@ uint8_t route_command(int pos) {
case READ_VOLTAGE: case READ_VOLTAGE:
{ {
// Validate that pos is within range
if (pos >= 2) { return 0; }
// Create a union to store the data // Create a union to store the data
union { union {
int16_t v; int16_t v;
@ -220,7 +228,7 @@ uint8_t route_command(int pos) {
} }
// Send the data // Send the data
return voltage.bytes[pos]; return voltage.bytes[1-pos];
} }
case READ_TERMPERATURE: case READ_TERMPERATURE:
{ {
@ -234,19 +242,51 @@ uint8_t route_command(int pos) {
} }
break; break;
case READ_FAN_SPEED: case READ_FAN_SPEED:
// Validate that pos is within range
if (pos >= 2) { return 0; }
// Union to hold the u16
if (context.fan == FAN1) { if (context.fan == FAN1) {
return fan1_history[0]; union {
uint16_t val;
uint8_t bytes[2];
} speed;
speed.val = fan1_history[fan1_history_index];
return speed.bytes[1-pos];
} else if (context.fan == FAN2) { } else if (context.fan == FAN2) {
return fan2_history[0]; union {
uint16_t val;
uint8_t bytes[2];
} speed;
speed.val = fan2_history[fan2_history_index];
return speed.bytes[1-pos];
} else { } else {
return 0; return 0;
} }
break; break;
case READ_BULK_FAN_SPEED: case READ_BULK_FAN_SPEED:
if (context.fan == FAN1) { if (context.fan == FAN1) {
return fan1_history[pos]; // Validate that pos is valid, if not return 0
if (pos >= 512) { return 0; }
// Calculate the index position
int16_t index = fan1_history_index - pos;
if (index < 0) { index = 511-pos; }
return fan1_history[index];
} else if (context.fan == FAN2) { } else if (context.fan == FAN2) {
return fan2_history[pos]; // Validate that pos is valid, if not return 0
if (pos >= 512) { return 0; }
// Calculate the index position
int16_t index = fan2_history_index - pos;
if (index < 0) { index = 511-pos; }
return fan2_history[index];
} else { } else {
return 0; return 0;
} }
@ -258,6 +298,7 @@ uint8_t route_command(int pos) {
} else if (context.fan == FAN2) { } else if (context.fan == FAN2) {
memset(fan2_history, 0, sizeof(fan2_history)); memset(fan2_history, 0, sizeof(fan2_history));
} }
return 0;
break; break;
case UNKNOWN_COMMAND: case UNKNOWN_COMMAND:
default: default:

View File

@ -66,6 +66,9 @@ typedef struct {
// Fan history variables // Fan history variables
extern volatile uint16_t fan1_history[512]; extern volatile uint16_t fan1_history[512];
extern volatile uint16_t fan2_history[512]; extern volatile uint16_t fan2_history[512];
// Fan history index variable
extern volatile uint16_t fan1_history_index;
extern volatile uint16_t fan2_history_index;
// Config // Config
extern volatile config_t config; extern volatile config_t config;

View File

@ -1,7 +1,7 @@
#include "fan_speeeed.h" #include "fan-speed.h"
#include "uart.h" #include "uart.h"
uint16_t timer_period_ms = 1; uint16_t timer_period_ms = 1000;
uint16_t fan_speed = 0; uint16_t fan_speed = 0;
volatile uint16_t fan1_edge_counter = 0; volatile uint16_t fan1_edge_counter = 0;
volatile uint16_t fan2_edge_counter = 0; volatile uint16_t fan2_edge_counter = 0;
@ -10,18 +10,21 @@ volatile uint16_t fan2_edge_counter = 0;
void init_TCA0() { void init_TCA0() {
TCA0.SINGLE.INTCTRL = TCA_SINGLE_OVF_bm ; TCA0.SINGLE.INTCTRL = TCA_SINGLE_OVF_bm ;
TCA0.SINGLE.CTRLA = TCA_SINGLE_ENABLE_bm | TCA_SINGLE_CLKSEL_DIV1024_gc ; /* Sysclk /1024 */ TCA0.SINGLE.CTRLA = TCA_SINGLE_ENABLE_bm | TCA_SINGLE_CLKSEL_DIV1024_gc ; /* Sysclk /1024 */
TCA0_update_period(timer_period_ms);
} }
void TCA0_update_period(uint16_t timer_period) { void TCA0_update_period(uint16_t period_ms) {
TCA0.SINGLE.PERBUF = (F_CPU * (1 / timer_period) / 1024); /* F_CPU * F_IRQ / TCA_prescaler */ float period_s = period_ms / 1E3; // Convert the ms to s
float frequency = 1/ period_s; // convert the period to a frequency
float perbuf_val = frequency * F_CPU / 1024; // F_IQR * F_CPU / TCA_prescaler
TCA0.SINGLE.PERBUF = (uint16_t)perbuf_val;
timer_period_ms = period_ms;
} }
// COUNTINGS / TIME = FREQUENCY // COUNTINGS / TIME = FREQUENCY
// FREQ / 2 = GIVES ACTUAL FREQ // FREQ / 2 = GIVES ACTUAL FREQ
// FREQ * SEC-IN-A-MINUTE(60) / FAN-BLADES // FREQ * SEC-IN-A-MINUTE(60) / FAN-BLADES
uint16_t RPM_calculation(uint16_t edge_counter, uint16_t time_ms) { uint16_t RPM_calculation(uint16_t edge_counter, uint16_t time_ms) {
fan_speed = (edge_counter / time_ms); fan_speed = (edge_counter / (float)((float)time_ms/1000.0) );
fan_speed = fan_speed/2; fan_speed = fan_speed/2;
fan_speed = fan_speed * 60/5; fan_speed = fan_speed * 60/5;
edge_counter = 0; edge_counter = 0;
@ -98,8 +101,25 @@ ISR(AC1_AC_vect){ // AC1 vec flag
// TIMER INTERUPT // TIMER INTERUPT
ISR (TCA0_OVF_vect) { ISR (TCA0_OVF_vect) {
cli(); cli();
RPM_calculation(fan1_edge_counter,timer_period_ms);
RPM_calculation(fan2_edge_counter,timer_period_ms); // Increment the index, or reset if it is at the top
if (fan1_history_index < 512) {
fan1_history_index++;
} else {
fan1_history_index = 0;
}
if (fan2_history_index < 512) {
fan2_history_index++;
} else {
fan2_history_index = 0;
}
// Calculate the fanspeed
fan1_history[fan1_history_index] = RPM_calculation(fan1_edge_counter, timer_period_ms);
fan2_history[fan2_history_index] = RPM_calculation(fan2_edge_counter, timer_period_ms);
// Reset the edge counter
fan1_edge_counter = 0; fan1_edge_counter = 0;
fan2_edge_counter = 0; fan2_edge_counter = 0;
TCA0.SINGLE.INTFLAGS = TCA_SINGLE_OVF_bm ; TCA0.SINGLE.INTFLAGS = TCA_SINGLE_OVF_bm ;

View File

@ -15,7 +15,7 @@ extern "C" {
#endif #endif
#include <stdbool.h> #include <stdbool.h>
#include <float.h> #include <float.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
@ -29,6 +29,14 @@ extern "C" {
* and inspiration form practice 6 for TCA0 setup * and inspiration form practice 6 for TCA0 setup
*/ */
// Fan history variables
extern volatile uint16_t fan1_history[512];
extern volatile uint16_t fan2_history[512];
// Fan history index variable
extern volatile uint16_t fan1_history_index;
extern volatile uint16_t fan2_history_index;
// INITALICE TIMER COUNTER // INITALICE TIMER COUNTER
void init_TCA0(); void init_TCA0();
@ -45,7 +53,7 @@ extern "C" {
// INIT AC0 TO COMPARE PD6 AND PD7 // INIT AC0 TO COMPARE PD6 AND PD7
void init_AC0(); void init_AC0();
// INIT AC1 TO COMPARE PD4 AND PD7 // INIT AC1 TO COMPARE PD4 AND PD7
void init_AC1(); void init_AC1();
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -14,7 +14,6 @@ extern "C" {
// Include the IO for I2C // Include the IO for I2C
#include "command-handler.h" #include "command-handler.h"
#include "uart.h"
#include <avr/interrupt.h> #include <avr/interrupt.h>
#include <avr/io.h> #include <avr/io.h>
#include <stdbool.h> #include <stdbool.h>

View File

@ -4,28 +4,39 @@
* *
* Created on March 6, 2024, 12:34 PM * Created on March 6, 2024, 12:34 PM
*/ */
#include "uart.h" #define F_CPU 4E6
#include "voltage.h"
#include <stdbool.h> // Include AVR specific libs
#define RTC_PERIOD (511)
#define DELAY_TIME 1000
#include "eeprom.h"
#include <avr/interrupt.h> #include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>
// Include standard C libraries
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#define F_CPU 4E6 #include <stdint.h>
// Include custom source files
#include "eeprom.h"
#include "voltage.h"
#include "command-handler.h" #include "command-handler.h"
#include "i2c.h" #include "i2c.h"
#include "themistor-temp.h" #include "themistor-temp.h"
#include "fan-speed.h"
// Only enable UART when required for debugging
#ifdef ENABLE_UART
#include "uart.h" #include "uart.h"
#include <avr/io.h> #endif
#include <stdint.h>
#include <util/delay.h>
// Fan history variables // Fan history variables
volatile uint16_t fan1_history[512] = {0}; volatile uint16_t fan1_history[512] = {0};
volatile uint16_t fan2_history[512] = {0}; volatile uint16_t fan2_history[512] = {0};
// Fan history index variable
volatile uint16_t fan1_history_index = 0;
volatile uint16_t fan2_history_index = 0;
// Default config is 500ms sample rate // Default config is 500ms sample rate
volatile config_t config = {500}; volatile config_t config = {500};
@ -33,24 +44,40 @@ volatile bool store_config = false;
int main() { int main() {
// Initialize functionality // Initialize functionality
init_uart((uint16_t)9600);
ADC0_init(); ADC0_init();
init_led(); init_alarm_gpio();
init_i2c(); init_i2c();
// Fanspeed
init_AC0();
init_AC1();
init_TCA0();
TCA0_update_period(config.ms_fanspeed_sample_rate);
// Only enable UART when required for debugging
#ifdef ENABLE_UART
init_uart((uint16_t)9600);
stdout = &USART_stream; stdout = &USART_stream;
#endif
// Read the stored config struct // Read the stored config struct
config = read_struct_from_EEPROM(); config = read_struct_from_EEPROM();
PORTB.DIRSET = PIN3_bm; // Enable interrupts
sei(); sei();
while (1) { while (1) {
// If we have made a config change, store it. // If we have made a config change, store it and recalculate the period.
if (store_config) { if (store_config) {
TCA0_update_period(config.ms_fanspeed_sample_rate);
write_struct_from_EEPROM(config); write_struct_from_EEPROM(config);
store_config = false; store_config = false;
} }
} }
// Check the temperature, and start the alarm if required
uint16_t thermistor_voltage = thermistor_voltage_read();
float temperature = calculate_thermistor_temp(thermistor_voltage);
bool start_alarm = voltage_threshold_bool(temperature, 40);
alert_voltage_threshold_exceeded(start_alarm);
} }

View File

@ -6,11 +6,11 @@
projectFiles="true"> projectFiles="true">
<itemPath>uart.h</itemPath> <itemPath>uart.h</itemPath>
<itemPath>voltage.h</itemPath> <itemPath>voltage.h</itemPath>
<itemPath>fan_speeeed.h</itemPath>
<itemPath>themistor-temp.h</itemPath> <itemPath>themistor-temp.h</itemPath>
<itemPath>command-handler.h</itemPath> <itemPath>command-handler.h</itemPath>
<itemPath>eeprom.h</itemPath> <itemPath>eeprom.h</itemPath>
<itemPath>i2c.h</itemPath> <itemPath>i2c.h</itemPath>
<itemPath>fan-speed.h</itemPath>
</logicalFolder> </logicalFolder>
<logicalFolder name="ExternalFiles" <logicalFolder name="ExternalFiles"
displayName="Important Files" displayName="Important Files"
@ -28,11 +28,11 @@
<itemPath>main.c</itemPath> <itemPath>main.c</itemPath>
<itemPath>uart.c</itemPath> <itemPath>uart.c</itemPath>
<itemPath>voltage.c</itemPath> <itemPath>voltage.c</itemPath>
<itemPath>fan_speeeed.c</itemPath>
<itemPath>thermistor-temp.c</itemPath> <itemPath>thermistor-temp.c</itemPath>
<itemPath>command-handler.c</itemPath> <itemPath>command-handler.c</itemPath>
<itemPath>i2c.c</itemPath> <itemPath>i2c.c</itemPath>
<itemPath>eeprom.c</itemPath> <itemPath>eeprom.c</itemPath>
<itemPath>fan-speed.c</itemPath>
</logicalFolder> </logicalFolder>
</logicalFolder> </logicalFolder>
<projectmakefile>Makefile</projectmakefile> <projectmakefile>Makefile</projectmakefile>

View File

@ -19,12 +19,15 @@ extern "C" {
#include <stdint.h> #include <stdint.h>
#include <math.h> #include <math.h>
#include <avr/io.h> #include <avr/io.h>
#define R_T0 10000 #define R_T0 100E3
#define T_0 298.15 #define T_0 298.15
#define B 3950 #define B 3950
#define R_1 1000 #define R_1 1000
#define ledpin PIN3_bm #define ledpin PIN3_bm
// Takes inn messured value
#define ALERT_PIN PIN3_bm
// Takes inn messured value // Takes inn messured value
// Calculates the temperature in celcius // Calculates the temperature in celcius
// Returns the thermistor themperature // Returns the thermistor themperature
@ -36,8 +39,8 @@ bool voltage_threshold_bool(float thermistor_temp, uint8_t max_temp);
void alert_voltage_threshold_exceeded(bool voltage_threshold_bool); void alert_voltage_threshold_exceeded(bool voltage_threshold_bool);
// Initialise led // Initialise alarm GPIO
void init_led(); void init_alarm_gpio();
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -1,8 +1,8 @@
#include "themistor-temp.h" #include "themistor-temp.h"
void init_led(){ void init_alarm_gpio(){
PORTB.DIRSET = ledpin; PORTB.DIRSET = ALERT_PIN;
} }
// The code is inspired by "Arduino thermistor guide" by valtentina Vogelman, 1 november 2023 // The code is inspired by "Arduino thermistor guide" by valtentina Vogelman, 1 november 2023
@ -14,7 +14,7 @@ float calculate_thermistor_temp(float thermistor_voltage){
float ln; float ln;
float T_thermistor; float T_thermistor;
float V_thermistor; float V_thermistor;
#define V_TOT 5 #define V_TOT 3.3
// Calculate Voltage over thermistor // Calculate Voltage over thermistor
V_thermistor = (V_TOT/1024)*thermistor_voltage; V_thermistor = (V_TOT/1024)*thermistor_voltage;
@ -44,9 +44,9 @@ bool voltage_threshold_bool(float thermistor_temp, uint8_t max_temp){
//print if the maximum threshold is exceeded. //print if the maximum threshold is exceeded.
void alert_voltage_threshold_exceeded(bool voltage_threshold_bool){ void alert_voltage_threshold_exceeded(bool voltage_threshold_bool){
if (voltage_threshold_bool){ if (voltage_threshold_bool){
printf("Error: maximum temperature exceeded"); //printf("Error: maximum temperature exceeded");
PORTB.OUTSET = ledpin; PORTB.OUTSET = ALERT_PIN;
} else{ } else{
PORTB.OUTCLR = ledpin; PORTB.OUTCLR = ALERT_PIN;
} }
} }

View File

@ -3,10 +3,10 @@
void ADC0_init(void) { void ADC0_init(void) {
/* Initializing ADC0 pin*/ /* Initializing ADC0 pin*/
/*Voltage reading on pin pd6*/ /*Voltage reading on pin pd2*/
PORTD.PIN6CTRL &= ~PORT_ISC_gm; PORTD.PIN2CTRL &= ~PORT_ISC_gm;
PORTD.PIN6CTRL |= PORT_ISC_INPUT_DISABLE_gc; /* Disable */ PORTD.PIN2CTRL |= PORT_ISC_INPUT_DISABLE_gc; /* Disable */
PORTD.PIN6CTRL &= PORT_PULLUPEN_bm; PORTD.PIN2CTRL &= PORT_PULLUPEN_bm;
/* Thermistor */ /* Thermistor */
PORTD.PIN3CTRL &= ~PORT_ISC_gm; PORTD.PIN3CTRL &= ~PORT_ISC_gm;
@ -43,7 +43,7 @@ uint16_t thermistor_voltage_read() {
} }
// Gets the value over thermistor // Gets the value over thermistor
uint16_t external_voltage_read() { uint16_t external_voltage_read() {
ADC0.MUXPOS = 0x06; // Read PD6 ADC0.MUXPOS = 0x02; // Read PD6
uint16_t adc_val = ADC0_read(); uint16_t adc_val = ADC0_read();
return adc_val; return adc_val;