Final project repo for ECE 495
Dependencies: Adafruit_GFX_MBED Adafruit_ILI9341 BurstSPI DS1820 mbed mbed-rtos ltc2991_lib
Revision 5:c1c710391df2, committed 2016-12-14
- Comitter:
- bdk9
- Date:
- Wed Dec 14 07:01:33 2016 +0000
- Parent:
- 4:84f847e99463
- Commit message:
- big update yo
Changed in this revision
diff -r 84f847e99463 -r c1c710391df2 display/Display.cpp --- a/display/Display.cpp Thu Dec 08 20:50:14 2016 +0000 +++ b/display/Display.cpp Wed Dec 14 07:01:33 2016 +0000 @@ -14,7 +14,7 @@ _needs_init = 1; } -void Display::next_screen() { +void Display::switch_screen() { if (_cur_screen_index == _num_screens - 1) { _cur_screen_index = 0; } @@ -32,3 +32,7 @@ } _cur_screen->update(); } + +void Display::error(char *msg) { + _cur_screen->error(msg); +} \ No newline at end of file
diff -r 84f847e99463 -r c1c710391df2 display/Display.h --- a/display/Display.h Thu Dec 08 20:50:14 2016 +0000 +++ b/display/Display.h Wed Dec 14 07:01:33 2016 +0000 @@ -13,8 +13,9 @@ Display(); void set_screens(Screen **screens, int num); - void next_screen(); + void switch_screen(); void update(); + void error(char *err); private:
diff -r 84f847e99463 -r c1c710391df2 display/screens/Screen.h --- a/display/screens/Screen.h Thu Dec 08 20:50:14 2016 +0000 +++ b/display/screens/Screen.h Wed Dec 14 07:01:33 2016 +0000 @@ -11,9 +11,8 @@ virtual void init() = 0; virtual void update() = 0; - -protected: - + virtual void error(char *msg) = 0; + int _id; Adafruit_ILI9341 *_tft;
diff -r 84f847e99463 -r c1c710391df2 display/screens/current/CurrentScreen.h --- a/display/screens/current/CurrentScreen.h Thu Dec 08 20:50:14 2016 +0000 +++ b/display/screens/current/CurrentScreen.h Wed Dec 14 07:01:33 2016 +0000 @@ -12,8 +12,8 @@ virtual void init(); virtual void update(); - - + virtual void error(char *msg); + }; #endif \ No newline at end of file
diff -r 84f847e99463 -r c1c710391df2 display/screens/temperature/TemperatureScreen.h --- a/display/screens/temperature/TemperatureScreen.h Thu Dec 08 20:50:14 2016 +0000 +++ b/display/screens/temperature/TemperatureScreen.h Wed Dec 14 07:01:33 2016 +0000 @@ -12,9 +12,7 @@ virtual void init(); virtual void update(); - -private: - + virtual void error(char *msg); };
diff -r 84f847e99463 -r c1c710391df2 display/screens/voltage/VoltageScreen.h --- a/display/screens/voltage/VoltageScreen.h Thu Dec 08 20:50:14 2016 +0000 +++ b/display/screens/voltage/VoltageScreen.h Wed Dec 14 07:01:33 2016 +0000 @@ -12,6 +12,7 @@ virtual void init(); virtual void update(); + virtual void error(char *msg); };
diff -r 84f847e99463 -r c1c710391df2 ltc2991_lib.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ltc2991_lib.lib Wed Dec 14 07:01:33 2016 +0000 @@ -0,0 +1,1 @@ +https://developer.mbed.org/users/bdk9/code/ltc2991_lib/#832fd12d477b
diff -r 84f847e99463 -r c1c710391df2 main.cpp --- a/main.cpp Thu Dec 08 20:50:14 2016 +0000 +++ b/main.cpp Wed Dec 14 07:01:33 2016 +0000 @@ -6,6 +6,25 @@ #include "VoltageScreen.h" #include "CurrentScreen.h" #include "Display.h" +#include "LTC2991.h" +#include <stdarg.h> + +struct SerialMessages { + char *error_msg; + char *next_screen; + char *fet_state; + char *fet_policy; + char *relay_state; + char *relay_policy; + char *fan_voltage; +}; + +struct PowerPolicy { + int fet_id; + int cur_id; + double amp_max; + PowerPolicy *next; +}; #define NUM_DS1820 1 #define PIN_DS1820 PC_0 @@ -14,31 +33,45 @@ DS1820* thermometers[NUM_DS1820]; Adafruit_ILI9341 tft(PA_13, PA_15, PA_14); Display disp; - -// IO RawSerial pc(USBTX, USBRX); DigitalOut led(LED1); -InterruptIn display_interrupt(PC_13); +DigitalOut *fetPin[6]; // THREADS Thread display_thread(osPriorityNormal, DEFAULT_STACK_SIZE, NULL); +Thread fast_data_thread(osPriorityNormal, DEFAULT_STACK_SIZE, NULL); Thread slow_data_thread(osPriorityNormal, DEFAULT_STACK_SIZE, NULL); Thread serial_thread(osPriorityNormal, DEFAULT_STACK_SIZE, NULL); // DATA VARIABLES -double temperatures[NUM_DS1820]; -double old_temperatures[NUM_DS1820]; +double temperatures[6]; +double old_temperatures[6]; +double voltages[4]; +double currents[10]; + +SerialMessages messages; +PowerPolicy *head; +PowerPolicy *tail; + +double max_system_current = 30.0; +DigitalOut relay_control(PA_0); //TODO update +PwmOut fan_control(PA_0); // TODO update pin (FET controlling fan) // DRAWING VARIABLES int margin; +int max_temp_plot = 75; int axes_x_cur; int axes_x_min, axes_x_max; int axes_y_bot, axes_y_top; -int temp_colors[3]; -int temp_label_y_pos[3]; -int temp_str_y_pos[3]; +int temp_colors[6]; +int temp_label_rect_y[6]; +char *temp_label_str[6]; +int temp_label_str_x[6]; +int temp_label_str_y[6]; +int temp_val_y[6]; bool plotFlag; - +bool errFlag = false; +char *errMsg; // FUNCTION DECLARATIONS int main(); @@ -53,20 +86,84 @@ // data read functions void read_temps(); // ISRs -void display_swap(); +void execute_command(char *cmd); void parse_command(); // helpers int scale_temp(double val, int min_domain, int max_domain, int min_range, int max_range); -char *int2bin(int x); + +void power_policy_init(); +void add_power_policy(int fet, int cur, double amps); + +int8_t ack; // 0 == ack, 1 == no ack +const uint16_t LTC2991_TIMEOUT=1000; //!< Configures the maximum timeout allowed for an LTC2991 read. + +//These pins for the nucleo nucleo f401re +LTC2991 *ltc0 = new LTC2991(I2C_SDA, I2C_SCL); +LTC2991 *ltc1 = new LTC2991(PB_3, PB_10); +LTC2991 *ltc2 = new LTC2991(PB_4, PA_8); +float readSingle(LTC2991 *l, int p); +float readDiff(LTC2991 *l, int upper_pin); +void ltc_init(); + + -void display_swap() { - if (display_interrupt) - disp.next_screen(); +void ltc_init() { + ack = 0; + + while (true) + { + int failures = 0; + pc.printf("booting LTC0\n"); + ack |= ltc0->LTC2991_register_write(LTC2991_I2C_ADDRESS, LTC2991_CHANNEL_ENABLE_REG, LTC2991_ENABLE_ALL_CHANNELS); //! Enables all channels + ack |= ltc0->LTC2991_register_write(LTC2991_I2C_ADDRESS, LTC2991_CONTROL_V1234_REG, 0x00); //! Sets registers to default starting values. + ack |= ltc0->LTC2991_register_write(LTC2991_I2C_ADDRESS, LTC2991_CONTROL_V5678_REG, 0x00); + ack |= ltc0->LTC2991_register_write(LTC2991_I2C_ADDRESS, LTC2991_CONTROL_PWM_Tinternal_REG, LTC2991_REPEAT_MODE); //! Configures LTC2991 for Repeated Acquisition mode + + if (ack != 0) { + pc.printf("Error: No Acknowledge LTC0. Check I2C Address.\n"); + failures++; + } + + pc.printf("booting LTC1\n"); + ack |= ltc1->LTC2991_register_write(LTC2991_I2C_ADDRESS, LTC2991_CHANNEL_ENABLE_REG, LTC2991_ENABLE_ALL_CHANNELS); //! Enables all channels + ack |= ltc1->LTC2991_register_write(LTC2991_I2C_ADDRESS, LTC2991_CONTROL_V1234_REG, 0x00); //! Sets registers to default starting values. + ack |= ltc1->LTC2991_register_write(LTC2991_I2C_ADDRESS, LTC2991_CONTROL_V5678_REG, 0x00); + ack |= ltc1->LTC2991_register_write(LTC2991_I2C_ADDRESS, LTC2991_CONTROL_PWM_Tinternal_REG, LTC2991_REPEAT_MODE); //! Configures LTC2991 for Repeated Acquisition mode + + if (ack != 0) { + pc.printf("Error: No Acknowledge LTC1. Check I2C Address.\n"); + failures++; + } + + pc.printf("booting LTC2\n"); + ack |= ltc2->LTC2991_register_write(LTC2991_I2C_ADDRESS, LTC2991_CHANNEL_ENABLE_REG, LTC2991_ENABLE_ALL_CHANNELS); //! Enables all channels + ack |= ltc2->LTC2991_register_write(LTC2991_I2C_ADDRESS, LTC2991_CONTROL_V1234_REG, 0x00); //! Sets registers to default starting values. + ack |= ltc2->LTC2991_register_write(LTC2991_I2C_ADDRESS, LTC2991_CONTROL_V5678_REG, 0x00); + ack |= ltc2->LTC2991_register_write(LTC2991_I2C_ADDRESS, LTC2991_CONTROL_PWM_Tinternal_REG, LTC2991_REPEAT_MODE); //! Configures LTC2991 for Repeated Acquisition mode + + if (ack != 0) { + pc.printf("Error: No Acknowledge LTC2. Check I2C Address.\n"); + failures++; + } + + if (failures > 0) { + wait_ms(500); + } else { + break; + } + } } + void display_task() { while(1) { - disp.update(); + if (errFlag) { + disp.error("A Fault Occured"); + errFlag = false; + } + else { + disp.update(); + } Thread::wait(1000); } } @@ -94,7 +191,38 @@ } void fast_data_task() { - + while(1) { + // Voltages + for (int i=0; i<4; i++) { + voltages[i] = readSingle(ltc2, i+5); + } + // Currents + currents[0] = readDiff(ltc0, 2); + currents[1] = readDiff(ltc0, 4); + currents[2] = readDiff(ltc0, 6); + currents[3] = readDiff(ltc0, 8); + currents[4] = readDiff(ltc1, 2); + currents[5] = readDiff(ltc1, 4); + currents[6] = readDiff(ltc1, 6); + currents[7] = readDiff(ltc1, 8); + currents[8] = readDiff(ltc2, 2); + currents[9] = readDiff(ltc2, 4); + + //Iterate over all power policies and act accordingly + PowerPolicy *p = head; + while (p->next != NULL) { + if (currents[p->cur_id] > p->amp_max) { + //Shutdown condition reached. Turn off until restart and alert + *(fetPin[p->fet_id]) = 0; + errFlag = 1; //Notify + sprintf(errMsg, "Overcurrent: %.2f on FET %d", currents[p->cur_id], p->fet_id); + pc.printf("PWR: ERR: %s\n", errMsg); + } + p = p->next; + } + + Thread::wait(10); + } } void serial_task() { @@ -117,21 +245,61 @@ pc.printf("Found %d device(s)\r\n\n", num_devices); } -char *int2bin(int x) { - static char b[33]; - b[0] = '\0'; - uint32_t z; - for (z = 2147483648; z > 0; z >>= 1) { - strcat(b, ((x & z) == z) ? "1" : "0"); - } - return b; -} char buff[64]; int loc = 0; + void execute_command(char *cmd) { - pc.printf("%s\n", cmd); + char msg_type[3]; + strncpy(msg_type, cmd, 1); + //pc.printf("%s\n", msg_type); + // ERROR MESSAGE + if (!strcmp(msg_type, messages.error_msg)) { + errFlag = true; + sprintf(errMsg, "%s", cmd); + } + // SWITCH SCREEN + else if (!strcmp(msg_type, messages.next_screen)) { + disp.switch_screen(); + } + // RELAY STATE + else if (!strcmp(msg_type, messages.relay_state)) { + int n; + sscanf(cmd, "R,%d\n", n); + relay_control = n; + } + // RELAY POLICY UPDATE + else if (!strcmp(msg_type, messages.relay_policy)) { + sscanf(cmd, "G,%2.2f\n", max_system_current); + } + // FET STATE + else if (!strcmp(msg_type, messages.fet_state)) { + int fet, n; + sscanf(cmd, "T,%d,%d\n", fet, n); + *(fetPin[fet]) = n; + } + // FET POLICY UPDATE + else if (!strcmp(msg_type, messages.fet_policy)) { + int fet_id; + int cur_id; + double amp_max; + sscanf(cmd, "C,%d,%d,%2.2f\n", fet_id, cur_id, amp_max); + add_power_policy(fet_id, cur_id, amp_max); + } + else if (!strcmp(msg_type, messages.fan_voltage)) { + double fan_volts; + sscanf(cmd, "F,%2.2f\n", fan_volts); + // TODO CONVERT TO PWM VALUE + int pwm_val = (int) ((fan_volts / 12.0)) * 100; + fan_control.period_us(100); + fan_control.pulsewidth_us(pwm_val); + } + // BAD MESSAGE - IMPROPER FORMAT + else { + // pc.printf("BAD MESSAGE\n"); + // lol u dumb + } } void parse_command() { @@ -144,15 +312,53 @@ } } +void power_policy_init() { + head->fet_id = 0; + head->cur_id = 0; + head->amp_max = 30.0; + head->next = NULL; + tail = head; + for (int i=1; i<6; i++) { + add_power_policy(i, i, 30.0); + } +} +void add_power_policy(int fet, int cur, double amps) { + PowerPolicy *pp; + pp->fet_id = fet; + pp->cur_id = cur; + pp->amp_max = amps; + pp->next = NULL; + tail->next = pp; + tail = pp; +} + +void serial_message_init() { + messages.error_msg = "E"; + messages.next_screen = "D"; + messages.fet_state = "T"; + messages.fet_policy = "C"; + messages.relay_state = "R"; + messages.relay_policy = "G"; + messages.fan_voltage = "F"; +} + int main() { - // Setup serial interrupts pc.attach(&parse_command); + // Initialize power policy + power_policy_init(); + + // Initialize serial message types + serial_message_init(); + // Setup temperature sensors ds1820_init(); + // Init LTCs + ltc_init(); + // Setup display tft.begin(); tft.fillScreen(BLACK); @@ -162,13 +368,22 @@ CurrentScreen cs(2, &tft); Screen *s[3] = {&ts, &vs, &cs}; disp.set_screens(s, 3); - display_interrupt.rise(&display_swap); + + //TODO: UPDATE THESE PINS TO BE ACCURATE + //Setup fet pins + *(fetPin[0]) = DigitalOut(PA_0); + *(fetPin[1]) = DigitalOut(PA_0); + *(fetPin[2]) = DigitalOut(PA_0); + *(fetPin[3]) = DigitalOut(PA_0); + *(fetPin[4]) = DigitalOut(PA_0); + *(fetPin[5]) = DigitalOut(PA_0); // Setup RTOS threads + fast_data_thread.start(fast_data_task); slow_data_thread.start(slow_data_task); wait_ms(1000); display_thread.start(display_task); - serial_thread.start(serial_task); + //serial_thread.start(serial_task); } @@ -191,12 +406,44 @@ temp_colors[0] = CYAN; temp_colors[1] = YELLOW; temp_colors[2] = GREEN; - temp_label_y_pos[0] = margin+9; - temp_label_y_pos[1] = margin+88; - temp_label_y_pos[2] = margin+168; - temp_str_y_pos[0] = margin+40; - temp_str_y_pos[1] = margin+120; - temp_str_y_pos[2] = margin+200; + temp_colors[3] = RED; + temp_colors[4] = BLUE; + temp_colors[5] = MAGENTA; + + temp_label_str[0] = "CPU"; + temp_label_str[1] = "AMBIENT"; + temp_label_str[2] = "MOTOR 1"; + temp_label_str[3] = "MOTOR 2"; + temp_label_str[4] = "MOTOR 3"; + temp_label_str[5] = "MOTOR 4"; + + temp_label_rect_y[0] = margin; + temp_label_rect_y[1] = margin+38; + temp_label_rect_y[2] = margin+78; + temp_label_rect_y[3] = margin+118; + temp_label_rect_y[4] = margin+158; + temp_label_rect_y[5] = margin+198; + + temp_label_str_x[0] = margin+30; + temp_label_str_x[1] = margin+10; + temp_label_str_x[2] = margin+10; + temp_label_str_x[3] = margin+10; + temp_label_str_x[4] = margin+10; + temp_label_str_x[5] = margin+10; + + temp_label_str_y[0] = margin+1; + temp_label_str_y[1] = margin+41; + temp_label_str_y[2] = margin+81; + temp_label_str_y[3] = margin+121; + temp_label_str_y[4] = margin+161; + temp_label_str_y[5] = margin+201; + + temp_val_y[0] = margin+21; + temp_val_y[1] = margin+61; + temp_val_y[2] = margin+101; + temp_val_y[3] = margin+141; + temp_val_y[4] = margin+181; + temp_val_y[5] = margin+221; // draw background _tft->fillScreen(BLACK); @@ -205,22 +452,14 @@ _tft->setCursor(155, margin); _tft->print("TEMPERATURE"); - _tft->fillRect(margin, margin, axes_x_min-2*margin, 30, temp_colors[0]); - _tft->setCursor(margin+33, temp_label_y_pos[0]); - _tft->setTextColor(BLACK); - _tft->print("CPU"); - - _tft->fillRect(margin, margin+80, axes_x_min-2*margin, 30, temp_colors[1]); - _tft->setCursor(margin+20, temp_label_y_pos[1]); - _tft->setTextColor(BLACK); - _tft->print("MOTOR"); - - _tft->fillRect(margin, margin+160, axes_x_min-2*margin, 30, temp_colors[2]); - _tft->setCursor(margin+10, temp_label_y_pos[2]); - _tft->setTextColor(BLACK); - _tft->print("AMBIENT"); - _tft->setTextSize(2); - + // draw temperature labels + for (int i=0; i<6; i++) { + _tft->fillRect(margin, temp_label_rect_y[i], axes_x_min-2*margin, 18, temp_colors[i]); + _tft->setCursor(temp_label_str_x[i], temp_label_str_y[i]); + _tft->setTextColor(BLACK); + _tft->print(temp_label_str[i]); + } + // x-axis _tft->drawFastHLine(axes_x_min, axes_y_bot, axes_x_max-axes_x_min, WHITE); // y-axis @@ -244,14 +483,14 @@ } int y_new, y_old; for (int i=0; i<NUM_DS1820; i++) { - _tft->fillRect(margin, temp_str_y_pos[i], axes_x_min-2*margin, 30, BLACK); + _tft->fillRect(margin, temp_val_y[i], axes_x_min-2*margin, 15, BLACK); char str[10]; sprintf(str, "%.2f C", temperatures[i]); - _tft->setCursor(margin, temp_str_y_pos[i]); + _tft->setCursor(margin+10, temp_val_y[i]); _tft->setTextColor(temp_colors[i]); _tft->print(str); - y_new = scale_temp(temperatures[i], 0, 150, axes_y_top, axes_y_bot); - y_old = scale_temp(old_temperatures[i], 0, 150, axes_y_top, axes_y_bot); + y_new = scale_temp(temperatures[i], 0, max_temp_plot, axes_y_top, axes_y_bot); + y_old = scale_temp(old_temperatures[i], 0, max_temp_plot, axes_y_top, axes_y_bot); _tft->drawLine(axes_x_cur, y_old, axes_x_cur+3, y_new, temp_colors[i]); } axes_x_cur += 3; @@ -261,18 +500,37 @@ } } +void TemperatureScreen::error(char *msg) { + _tft->fillScreen(RED); + _tft->setCursor(_tft->width() / 2 - 50, _tft->height() / 2); + _tft->setTextColor(BLACK); + _tft->print(msg); + wait_ms(3000); + init(); +} + // VOLTAGE DISPLAY VoltageScreen::VoltageScreen(int id, Adafruit_ILI9341 *tft) : Screen(id, tft) { } void VoltageScreen::init() { - _tft->fillScreen(RED); + _tft->fillScreen(BLACK); + } void VoltageScreen::update() { + } +void VoltageScreen::error(char *msg) { + _tft->fillScreen(RED); + _tft->setCursor(_tft->width() / 2 - 50, _tft->height() / 2); + _tft->print(msg); + wait_ms(3000); + init(); +} + @@ -284,4 +542,99 @@ } void CurrentScreen::update() { -} \ No newline at end of file + +} + +void CurrentScreen::error(char *msg) { + _tft->fillScreen(RED); + _tft->setCursor(_tft->width() / 2 - 50, _tft->height() / 2); + _tft->print(msg); + wait_ms(3000); + init(); +} + + +// LTC READING +// read single pins 1 - 8 +float readSingle(LTC2991 *l, int p) { + int v_control_reg, v_msb; + switch (p) { + case 1: + v_control_reg = LTC2991_CONTROL_V1234_REG; + v_msb = LTC2991_V1_MSB_REG; + break; + case 2: + v_control_reg = LTC2991_CONTROL_V1234_REG; + v_msb = LTC2991_V2_MSB_REG; + break; + case 3: + v_control_reg = LTC2991_CONTROL_V1234_REG; + v_msb = LTC2991_V3_MSB_REG; + break; + case 4: + v_control_reg = LTC2991_CONTROL_V1234_REG; + v_msb = LTC2991_V4_MSB_REG; + break; + case 5: + v_control_reg = LTC2991_CONTROL_V5678_REG; + v_msb = LTC2991_V5_MSB_REG; + break; + case 6: + v_control_reg = LTC2991_CONTROL_V5678_REG; + v_msb = LTC2991_V6_MSB_REG; + break; + case 7: + v_control_reg = LTC2991_CONTROL_V5678_REG; + v_msb = LTC2991_V7_MSB_REG; + break; + case 8: + v_control_reg = LTC2991_CONTROL_V5678_REG; + v_msb = LTC2991_V8_MSB_REG; + break; + } + + int8_t data_valid; + int16_t code; + float voltage; + ack = 0; + ack |= l->LTC2991_register_set_clear_bits(LTC2991_I2C_ADDRESS, v_control_reg, 0x00, LTC2991_V1_V2_DIFFERENTIAL_ENABLE | LTC2991_V1_V2_TEMP_ENABLE); + ack |= l->LTC2991_adc_read_new_data(LTC2991_I2C_ADDRESS, v_msb, &code, &data_valid, LTC2991_TIMEOUT); + voltage = l->LTC2991_code_to_single_ended_voltage(code, LTC2991_SINGLE_ENDED_lsb); + if (ack != 0) { + pc.printf("Error: No Acknowledge\n"); + } + return voltage; +} + +float readDiff(LTC2991 *l, int upper_pin) { + int v_control_reg, v_msb; + switch (upper_pin) { + case 2: + v_control_reg = LTC2991_CONTROL_V1234_REG; + v_msb = LTC2991_V2_MSB_REG; + break; + case 4: + v_control_reg = LTC2991_CONTROL_V1234_REG; + v_msb = LTC2991_V4_MSB_REG; + break; + case 6: + v_control_reg = LTC2991_CONTROL_V5678_REG; + v_msb = LTC2991_V6_MSB_REG; + break; + case 8: + v_control_reg = LTC2991_CONTROL_V5678_REG; + v_msb = LTC2991_V8_MSB_REG; + break; + } + int8_t data_valid; + int16_t code; + float voltage; + ack = 0; + ack |= l->LTC2991_register_set_clear_bits(LTC2991_I2C_ADDRESS, v_control_reg, LTC2991_V1_V2_DIFFERENTIAL_ENABLE, LTC2991_V1_V2_TEMP_ENABLE); + ack |= l->LTC2991_adc_read_new_data(LTC2991_I2C_ADDRESS, v_msb, &code, &data_valid, LTC2991_TIMEOUT); + voltage = l->LTC2991_code_to_differential_voltage(code, LTC2991_DIFFERENTIAL_lsb); + if (ack != 0) { + pc.printf("Error: No Acknowledge.\n"); + } + return voltage; +} \ No newline at end of file