LEX_Threaded_Programming
Dependencies: Heater_V2 MODSERIAL Nanopb FastPWM ADS8568_ADC
main.cpp
- Committer:
- justinbuckland
- Date:
- 2020-03-30
- Revision:
- 36:fef05d541679
- Parent:
- 35:aa35c6325dac
File content as of revision 36:fef05d541679:
#include "mbed.h" #include "pb.h" #include "pb_decode.h" #include "pb_encode.h" #include "MODSERIAL.h" #include "ADS8568_ADC.h" #include "Heater.h" #include "FastPWM.h" #include "memspcr.pb.h" #include <vector> #include <iterator> #define BUFFER_SIZE 8192 #define PRESSURE_SMOOTH_FACTOR 0.9 //UID lookup address and pointer #define UID_ADDR 0x1FFF7A10 unsigned long *uid = (unsigned long *) UID_ADDR; //UID and drive board calibration table #define UID_TABLE_LENGTH 4 int drive_board_serial_number[UID_TABLE_LENGTH] = {1, 2, 3, 4}; unsigned long drive_board_uid[UID_TABLE_LENGTH][3] = {{0x005B0060, 0x32375101, 0x32363531}, {0x00530028, 0x32375116, 0x30333732}, // updated board 2 UID {0x0051003D, 0x32375114, 0x30333732}, {0x00520060, 0x32375101, 0x32363531}, {0x00570060, 0x32375101, 0x32363531}}; float drive_board_cal[UID_TABLE_LENGTH][2][2] = {{{0.098846, 10.190057}, {0.060713, 10.208784}}, {{0.060987, 10.154840}, {0.033058, 10.239591}}, {{0.014312, 10.405662}, {0.000000, 1.0000000}}, {{0.055152, 10.062970}, {0.114355, 10.123188}}}; Heater * heater; float r_gradient; //setpoint setting MODSERIAL pc(PA_9, PA_10, BUFFER_SIZE); //mcu TX, RX, BUFFER_SIZE byte TX and RX buffers ADS8568_ADC adc(PB_15, PB_14, PB_13, PB_12, PC_15, PC_0, PC_1, PC_2, PC_3); I2C i2c(PB_7, PB_8); //SDA, SCL Timer timer; DigitalIn adc_busy(PA_8); //Busy interrupt sig# //Fluidic Control AnalogIn pressure_0(PA_0); AnalogIn pressure_1(PA_1); DigitalOut pump(PA_4); DigitalOut valve_0(PA_5); DigitalOut valve_1(PA_6); float pressure_in = 0.1; // 0.1 - 0.9 corresponds to 0 - 15psi float pressure_out = 0.1; //Heater Control FastPWM drive_1(PC_9); FastPWM drive_2(PC_8); FastPWM guard_1(PC_7); FastPWM guard_2(PC_6); //ADC channels for heater current and voltage measurements int i_port_1 = 0; int i_port_2 = 2; int v_port_1 = 1; int v_port_2 = 3; //Heater ID: heater 1 is nearer liquid sense location, heater 2 is other location int heater_ID; //Illumination LED Control //Indicator LEDs DigitalOut hb_led(PC_13); //Red DigitalOut led_0(PC_4); //Green DigitalOut led_1(PC_5); //Red //Camera and LED drive DigitalOut camTrigger(PB_2); //Trigger camera DigitalOut ledDrive(PB_4); //Drive LED for fluorescence detection //User buttons DigitalIn user_0(PB_0); DigitalIn user_1(PB_1); BusOut converts(PC_0, PC_1, PC_2, PC_3); //Threads Thread heater_control(osPriorityHigh); Thread logging_thread(osPriorityAboveNormal); Thread pressure_thread(osPriorityNormal); //Tickers Ticker heat_tick; Ticker pressure_tick; Ticker log_tick; //Flags EventFlags flags; //Flags: // 0 => update heater // 1 => log state // 2 => read pressure bool triggered_flag; bool status = true; //Configuration data memspcr_ExperimentConfiguration exp_config = memspcr_ExperimentConfiguration_init_zero; int buffer_length; size_t message_length; uint8_t buffer[BUFFER_SIZE]; //Functions for reading and decoding the message__________________________________________________ void read_message() { if (pc.scanf("%d",&message_length) < 0){pc.printf("# Error reading message length");} size_t buffer_length = sizeof(buffer); if (message_length > buffer_length) { pc.printf("# Message length exceeds buffer. \n Input configuration file\n"); read_message(); return; } pc.printf("# Message is %d chars long, buffer length is %d\n",message_length,buffer_length); unsigned int c; for (int i = 0; i < message_length; i++) { pc.scanf("%02X",&c); buffer[i] = (char) c; } } void decode_message() { // Create a stream that reads from the buffer. pb_istream_t istream = pb_istream_from_buffer(buffer, message_length); //Now we are ready to decode the message. status = pb_decode(&istream, memspcr_ExperimentConfiguration_fields, &exp_config); // Check for errors... if (!status) { pc.printf("# Decoding failed: %s\n", PB_GET_ERROR(&istream)); } } bool decode_callback(pb_istream_t *stream, const pb_field_t *field, void **arg) { vector <memspcr_ThermalStep> * dest = (vector <memspcr_ThermalStep> *)(*arg); memspcr_ThermalStep result = memspcr_ThermalStep_init_zero; status = pb_decode(stream, memspcr_ThermalStep_fields, & result); if (!status) { pc.printf("# Decode callback failed\n"); } dest->push_back(result); //CHECK: Does result get copied into the vector? return true; } //Ticking functions_________________________________________________________________ void temp_trigger() { //This function triggers a temperature update. //N.B. update cannot be called directly from a ticker as tickers and //reading the ADC both rely on interrupts. flags.set(0x1); } void log_trigger() { flags.set(0x2); } //Other functions__________________________________________________________________ void temp_control() { while(1){ flags.wait_any(0x1,osWaitForever,true); heater->read(); heater->update(); wait_us(200);//Give other threads time to get selected } } void log_state() { while(1){ flags.wait_any(0x2,osWaitForever,true); //Read and control pressure pressure_in = pressure_in * PRESSURE_SMOOTH_FACTOR + (1 - PRESSURE_SMOOTH_FACTOR) * pressure_1.read(); pressure_out = pressure_out * PRESSURE_SMOOTH_FACTOR + (1 - PRESSURE_SMOOTH_FACTOR) * pressure_0.read(); if (pressure_in < exp_config.fluidics.pressure_sensor_setpoint_adc - exp_config.fluidics.pressure_sensor_hysteresis_adc) { led_1 = 1; pump = 1; } else if (pressure_in > exp_config.fluidics.pressure_sensor_setpoint_adc) { led_1 = 0; pump = 0; } //Output time, R_avg, R_ref, R_var, error, error_integrated, duty cycle, input pressure, output pressure pc.printf("%10d,%10d,%10.6f,%10.6f,%10.6f,%10.6f,%10.6f,%10.6f,%10.6f,%10.6f\n", heater_ID, timer.read_ms(), heater->Get_R_avg(), heater->Get_R_ref(), heater->Get_R_var(), heater->Get_error(), heater->Get_error_integrated(), heater->Get_D(), pressure_in, pressure_out); wait_us(200);//Give other threads time to get selected } } void set_point_routine(std::vector<memspcr_ThermalStep> profile) { int curr_time; vector <memspcr_ThermalStep>::iterator it_prev, it = profile.begin(); if (it->elapsed_time_ms != 0) { pc.printf("# Error: the first point in the profile should be at time 0.\n"); return; } it++; for (it_prev = profile.begin(); it < profile.end(); it ++, it_prev++){ triggered_flag = false; r_gradient = (it->resistance_set_point - it_prev->resistance_set_point)/(it->elapsed_time_ms - it_prev->elapsed_time_ms); while ((curr_time = timer.read_ms()) <= it->elapsed_time_ms){ heater->Set_ref(it_prev->resistance_set_point + r_gradient * (curr_time - it_prev->elapsed_time_ms)); if (!triggered_flag && (it->camera_offset_ms != 0) && (curr_time > it_prev->elapsed_time_ms + it->camera_offset_ms)) { //Start camera exposure and turn on LED if camera_offset_ms is non-zero camTrigger = 0; wait_us(10); camTrigger = 1; led_0 = 1; ledDrive = 1; triggered_flag = true; } wait_us(200); } //Stop camera exposure and turn off LED at end of time segment camTrigger = 0; led_0 = 0; ledDrive = 0; } } int main() { int i_board = -1; int i_heater; float drive_cal_a, drive_cal_b; pc.baud(115200); adc.init(); pc.printf("\r\nUnique ID: %08X %08X %08X \r\n", uid[0], uid[1], uid[2]); for (int i = 0; i < UID_TABLE_LENGTH; i++) { if (uid[0]==drive_board_uid[i][0] && uid[1]==drive_board_uid[i][1] && uid[2]==drive_board_uid[i][2]) { i_board = i; i = UID_TABLE_LENGTH; } } buffer_length = sizeof(buffer)/sizeof(uint8_t); pc.printf("# Input [CONFIGURATION] file\n"); //set up nanopb std::vector<memspcr_ThermalStep> profile; exp_config.profile.funcs.decode = decode_callback; exp_config.profile.arg = &profile; //read and decode configuration read_message(); pc.printf("# Message read\n"); decode_message(); pc.printf("# Message decoded\n"); //Select heater if (exp_config.selected_heater == memspcr_ExperimentConfiguration_Heater_HEATER_1) i_heater = 0; else if (exp_config.selected_heater == memspcr_ExperimentConfiguration_Heater_HEATER_2) i_heater = 1; else { pc.printf("# Error - no heater has been selected\n"); return 1; } heater_ID = i_heater + 1; //Set drive ADC->Resistance calibration coefficients (default: no change if board not found) drive_cal_a = drive_board_cal[i_board][i_heater][0]; drive_cal_b = drive_board_cal[i_board][i_heater][1]; pc.printf("# Heater: %d\n", heater_ID); pc.printf("# Drive board calibration: %10.6f, %10.6f\n", drive_cal_a, drive_cal_b); //Define heaters Heater * heater_1 = new Heater(i_port_1, v_port_1, drive_cal_a, drive_cal_b, & drive_1, & guard_1, & adc, adc_busy, exp_config.thermal); Heater * heater_2 = new Heater(i_port_2, v_port_2, drive_cal_a, drive_cal_b, & drive_2, & guard_2, & adc, adc_busy, exp_config.thermal); if (i_heater == 0) heater = heater_1; else heater = heater_2; //Start pressure control pc.printf("# Pressure setpoint: %10.6f hystersess: %10.6f\n",exp_config.fluidics.pressure_sensor_setpoint_adc, exp_config.fluidics.pressure_sensor_hysteresis_adc); pc.printf("# Waiting for signal to begin [PRESSURE] control (type p or press button 0)\n"); while (pc.getcNb()!='p' && !user_0); pc.printf("# Pressure control start signal received\n"); //Start logging (pressure control takes place within logging thread) logging_thread.start(& log_state); log_tick.attach_us(& log_trigger,exp_config.logging_interval_ms * 1000); //Start temperature control pc.printf("# Waiting for signal to begin [THERMAL] control (type s or press button 0)\n"); while (pc.getcNb()!='s' && !user_0); pc.printf("# Thermal control start signal received\n"); heater->Set_ref(0.0); heater_control.start(& temp_control); heat_tick.attach_us(& temp_trigger,exp_config.thermal.thermal_control_loop_interval_ms * 1000); pc.printf("# Starting routine on drive board: %d\n",drive_board_serial_number[i_board]); pc.printf("heater id, time (ms), R_avg (Ohm), R_set (Ohm), R_var (Ohm), Err (Ohm), Err_int (Ohm.ms), Duty cycle, P0 (ADC), P1 (ADC)\n"); timer.start(); set_point_routine(profile); //Turn off heat_tick.detach(); log_tick.detach(); wait(1); heater->turn_off(); pc.printf("# Finished\n"); return 0; }