LNLS Driver Heaters DCM Firmware with two sockets: - HTTP server at port 80 - TCP socket at port 5757 for EPICS
Dependencies: mbed mbed-rtos AMC7812B EthernetInterface TextLCD
Firmware for DCM heaters driver - 8 channel, 12V/1.5A, PWM controlled with interlock and failure diagnostics
Mauricio Martins Donatti
Brazilian Synchrotron Light Laboratory
Electronics Support Group - GAE
mauricio.donatti@lnls.br
Extra scripts on Github page:
1. Driver_DCM_Socket.py: Open a socket and comunicate with the Driver.
2. Find_IP.py: Search a subdomain for devices (IPs) with a TCP Server Socket on the specified port.
3. firmware.txt: device firmware link (MBED).
4. index.html: HTTP server GET answer - html + JS.
main.cpp
- Committer:
- mmdonatti
- Date:
- 2021-08-06
- Revision:
- 3:820e3a42c06b
- Parent:
- 2:7a49ed074968
File content as of revision 3:820e3a42c06b:
/********************************************************************* * * Driver Heaters DCM 8 channel - v4 (improvements) * * Mauricio Martins Donatti * mauricio.donatti@lnls.br * * Electronic Support Group - GAE * Brazilian Synchrotron Light Laboratory (LNLS) * Brazilian Center for Research in Energy and Materials (CNPEM) * * Jan 2021 * * References: * - AMC7812B datasheet: http://www.ti.com/lit/ds/symlink/amc7812b.pdf * - Modification inside ethernet library: https://os.mbed.com/questions/1602/How-to-set-the-TCPIP-stack-s-hostname-pr/ * - VERY IMPORTANT: https://os.mbed.com/questions/61544/threaded-TCP-server-with-multi-port-it-r/ * *******************************************************************/ #define SUPPLY_24V //#define CAL #include "mbed.h" #include "TextLCD.h" #include "EthernetInterface.h" #include "amc7812b.h" #define ERROR_INTERFACE //#define DEBUG_INTERFACE #include "definitions.h" #include "HTTP_SERVER.h" #define VERSION "v4.1-2021-07\0" //Firmware Version #define DEVICE_NAME "DH-8CH-001\0" //Device Name - Ethernet default hostname #define PORT 6767 //Socket Port (EPICS data) //SPI constructor SPI spi(MOSI,MISO,SCLK); //mosi, miso, sclk Serial pc(USBTX, USBRX, 115200); //Digital Output constructors DigitalOut cs_u4(CS_U4); DigitalOut cs_u5(CS_U5); DigitalOut amc_reset(RST); DigitalOut dac_clr(DAC_CLR); DigitalOut cnvt_u5(CNVT_U5); DigitalOut cnvt_u4(CNVT_U4); //Digital Input constructors DigitalIn al_u4(AL_U4); DigitalIn al_u5(AL_U5); //Interrupt Input constructors InterruptIn dav_u4(DAV_U4); InterruptIn dav_u5(DAV_U5); //Digital output indicators DigitalOut blink(LED4); //Heartbeat at LED4 DigitalOut socket_led(LED2); //Socket Connection LED DigitalOut led_cfg(LED3); //Configuration LED - ON only in configuration mode (adjusting current limit) DigitalOut server_led(LED1); //HTTP Server LED DigitalOut phy_rst(P1_28); //Ethernet PHY reset DigitalOut eth_led1(p29); //Ethernet LED1 DigitalOut eth_led2(p30); //Ethernet LED2 //LCD Construtor Serial display(LCD_TX, LCD_RX); //LCD module initialization //Timer Tickers Ticker start_convertion; //Triggers ADC convertion Timer t; //read ms timer to display and heartbeat functions //There is a configuration file that can be accessed through usb in order to adjust current limits LocalFileSystem local("local"); //Create the local filesystem under the name "local" //Variable Initialization EthernetInterface eth; //ethernet interface TCPSocketServer server; //Socket TCPSocketConnection client; //Client //Create the variables structure for 8 channels (index 0 to 7) channel CH[8]; //Create two spi global buffers - tx and rx //LPC1768 SPI works in 12 bits. AMC7812B spi works in 24 bits. union spi_buf{ //the same buffer may be expressed in two bytes (uint8_t) or a 16bit word (uint16_t) uint8_t byte[2]; uint16_t data; }rx,tx; FILE *cfg_file; //Config file variable FILE *html_file; //Html file variable int tmp,i; //auxiliary integers int LCD_index=0; //LCD index (displayed channel changes from 1 to 8) char LCD_buffer[40]; //LCD char buffer char cfg=0; //variable to identify config mode (config mode = current limit adjust mode) float mult = 10; //multiplier used in config mode char flag_adj=0; //flag to indicate adjust/config mode //int r,c; //auxiliary integers to LCD row and column uint8_t flag_end_u4,flag_end_u5; //flags to indicate AD end of convertion uint8_t register_amc; //8 bit variable to store AMC register to read/write uint16_t reg_aux; //Aux 16 bit variable used in spi read/write functions //global variables for socket message treatment int ch_msg_idx,n; char tmp_char; float ilimit_msg; Thread main_thread,server_thread,socket_thread; //threads instances Thread display_thread; //display thread (v3) volatile uint8_t new_cfg; //new config to save to file uint8_t display_status; uint8_t server_init=0,socket_init=0; //sockets init flags HttpServer httpsvr; //http server instance char socket_buffer[200]; //socket receive buffer char send_buffer[100]; //socket send buffer int receive_return; //receive return for socket loop thread char dev_name[30]; //device name string //Display Functions void error(void); //Turn Red Led - Error Status void normal(void); //Turn Green Led - Normal Status void disabled(void); //Turn (Red + Green) - Channel disabled void write_LCD(void); //Write to LCD Function void reset_config(void); //Reset config buttons status void clear_lcd(void); //Clear LCD Function void heart(void); //Toggle function to heartbeat //AMC7812B ADC and DAC functions void fast_read_U5(void); //U5 SPI fast read (returns previous transfer result) void fast_read_U4(void); //U4 SPI fast read (returns previous transfer result) void read_U5(void); //U5 SPI simple read - Takes two times the fast read void read_U4(void); //U4 SPI simple read - Takes two times the fast read void write_U5(void); //U5 SPI write void write_U4(void); //U4 SPI write void setup(void); //Initialization (display and variables) void amc_setup(void); //AMC7812B setup (U4 and U5) //Config and Output functions void adj_ilimit(int channel,float value); //Adjust current limit void fail_out(int channel,int value); //Set/Reset failure output //End of convertion interruptions void end_conv_u4(void); //U4 end of convertion function (interruption called) void end_conv_u5(void); //U5 end of convertion function (interruption called) //ADC convertion Trigger Functions void trigger_conv(void); //Trigger convertion function (start U4 and U5 convertion) - Ticker called void trigger_u4(void); //Trigger U4 only (not used) void trigger_u5(void); //Trigger U5 only (not used) extern "C" void mbed_reset(); //mbed reset function void message_treatment(void); //socket data received treatment //Sockets functions void socket_start(); //initiate socket instances void server_loop(void); //Server threaded loop - Port 80 void socket_loop(void); //Socket threaded loop - Port 5757 //Thread loops void main_loop(void); //main thread (real-time priority) - deals with the AMC devices void display_loop(void); //display update thread - deals with buttons and LCD (uart) volatile int save_cfg_time; char html_page[HTML_MAX_SIZE]; int html_page_size; //main function int main() { //heartbeat.attach(&heart,HEARTBEAT_DELAY); //attach heartbeat ticker t.start(); // Reading webserver file wait_ms(10); //Wait powerup html_file = fopen("/local/index.htm","r"); // Open "index.html" on the local file system for reading if(html_file==NULL){ //If file doesnt exist html_page_size = sprintf(html_page,"ERROR: File Not Found"); ERROR_PRINTF("index.htm file not found at local file system!"); fclose(html_file); //close html file } else { //File exists fseek(html_file, 0, SEEK_SET); html_page_size = 0; while (!feof(html_file)) html_page[html_page_size++]= getc(html_file); if(feof(html_file)) html_page_size--; fclose(html_file); //close html file } amc_setup(); //Setup AMC7812B setup(); //Initialize LCD and variables dav_u4.fall(&end_conv_u4); //attach the address of the U4 end of convertion function to the falling edge dav_u5.fall(&end_conv_u5); //attach the address of the U5 end of convertion function to the falling edge start_convertion.attach(&trigger_conv,CONV_DELAY); //attach ticker to trigger convertions - USED ONLY IN DIRECT MODE //trigger_conv(); //Start convertion - USED ONLY IN AUTO MODE if (0 == eth.init())//Use DHCP { eth.setName(dev_name); } else { clear_lcd(); display.printf("HW ERROR: eth conn"); //HW ethernet error - probably PHY broken ERROR_PRINTF("Ethernet Connection Hardware Error!"); //Turn LED 1 Red and Green - ETH HW Error display.putc(0xFE); display.putc(0x5A); display.putc(0x01); display.putc(0x03); } main_thread.set_priority(osPriorityRealtime); //Start AMCs thread with high high high priority server_thread.set_priority(osPriorityNormal); //HTTP server thread normal priority socket_thread.set_priority(osPriorityNormal); //Socket server (EPICS) normal priority display_thread.set_priority(osPriorityNormal); //Socket server (EPICS) normal priority display_thread.start(display_loop); //Start AMC loop main_thread.start(main_loop); //Start AMC loop while(1) { if(new_cfg==1 && t.read_ms() - save_cfg_time >= SAVE_CFG_DELAY_MIN) //File must be saved by the main thread. new_cfg is a flag indicating new data mus be saved { cfg_file = fopen("/local/lim.cfg", "w"); //Open "lim.cfg" on the local file system for writing fprintf(cfg_file,"Channel Configuration - Current Limit and Enable\n"); //Write header fprintf(cfg_file,"%s\n",dev_name); for(tmp=0;tmp<8;tmp++) { fprintf(cfg_file,"%d %3.2f %d\n",tmp+1,CH[tmp].limit,CH[tmp].enable); //Write current limits to file } fclose(cfg_file); //close file new_cfg=0; //reset flag } if(eth.is_connected()) //if eth connected { eth_led2 = !eth_led2; //toggle led2 eth_led1 = 1; //turn on led1 if(server_init == 0) //initiate http server the first time { httpsvr.init(html_page,html_page_size); server_init = 1; //turn flag on - Server initiated server_thread.start(server_loop); //run thread - monitoring port 80 } if(socket_init == 0) //initiate socket server (PORT 5757) - EPICS { socket_start(); socket_init = 1; //turn flag on socket_thread.start(socket_loop); //run thread - monitoring port 5757 } } else //connect ethernet { if(eth_led1) //eth_led serves also as flag { eth.disconnect(); //disconnect interface eth_led1=0; //turn leds off eth_led2=0; //Turn Display LED red display.putc(0xFE); display.putc(0x5A); display.putc(0x01); display.putc(0x02); } if (0 == eth.connect()) //once connected, display IP and hostname on LCD { //Turn Display LED green display.putc(0xFE); display.putc(0x5A); display.putc(0x01); display.putc(0x01); } } } } void display_loop(void) { int display_time,heart_time; char blink_led,byte_read; display_time = t.read_ms(); heart_time = t.read_ms(); blink_led = 0x01; while(1) { if(t.read_ms()- display_time >= DISPLAY_DELAY*1000) { display_time = t.read_ms(); display_status = 0; if(cfg == 0) { //If not in config mode LCD_index = (LCD_index+1)%8; //Update index write_LCD(); //call write_LCD() } } if(t.read_ms()- heart_time >= HEARTBEAT_DELAY*1000) { heart_time = t.read_ms(); heart(); display.putc(0xFE); display.putc(0x5A); display.putc(0x02); display.putc(blink_led); blink_led = blink_led ^ 0x01; } if(display.readable()) { byte_read = display.getc(); if(byte_read=='B')//UP SQUARE BUTTON { if(cfg==0) { display_time = t.read_ms(); display_status=1; clear_lcd(); if(eth_led1 == 1) display.printf("%-16s%-16s",eth.getIPAddress(),eth.getName()); else display.printf("ETH DISCONNECTED"); } else { reset_config(); } } if(byte_read=='A')//UP BUTTON { display_status=0; if(cfg==0) //If not in CONFIG mode { display_time = t.read_ms(); clear_lcd(); LCD_index = (LCD_index+1)%8; //increment LCD index write_LCD(); //write to LCD } else //If CONFIG mode { if(CH[LCD_index].limit+mult <= CURR_MAX_LIMIT) //Verify higher current bound condition CH[LCD_index].limit = CH[LCD_index].limit + mult; //Use multiplier to increment current display.putc(0xFE); display.putc(0x47); display.putc(0xC); display.putc(0x2); display.printf("%3.2f",CH[LCD_index].limit); display.putc(0xFE); display.putc(0x47); if(cfg==1) //if config = 1, blink first digit display.putc(0xB+cfg); else //else, blink second or third digit (after dot) display.putc(0xC+cfg); display.putc(0x2); } } if(byte_read=='C')//DOWN BUTTON { display_status=0; if(cfg==0) //If not in CONFIG mode { display_time = t.read_ms(); clear_lcd(); LCD_index = (LCD_index-1); //decrement LCD index if(LCD_index==-1) //Verify lower bound LCD_index = 7; write_LCD(); //write to LCD } else //If CONFIG mode { if(mult<=CH[LCD_index].limit) //Verify lower current bound condition CH[LCD_index].limit = CH[LCD_index].limit - mult; //Use multiplier to decrement current display.putc(0xFE); display.putc(0x47); display.putc(0xC); display.putc(0x2); display.printf("%3.2f",CH[LCD_index].limit); display.putc(0xFE); display.putc(0x47); if(cfg==1) //if config = 1, blink first digit display.putc(0xB+cfg); else //else, blink second or third digit (after dot) display.putc(0xC+cfg); display.putc(0x2); } } if(byte_read=='D')//DOWN SQUARE BUTTON { if(cfg<4&&display_status==0) //If CONFIG<4, go to next config { led_cfg=1; //turn config led on cfg = cfg++; //increment config variable mult = mult/10; //adjust multiplier (divided by 10 each config increment) display.putc(0xFE); display.putc(0x47); if(cfg==1) //if config = 1, blink first digit display.putc(0xB+cfg); else //else, blink second or third digit (after dot) display.putc(0xC+cfg); display.putc(0x2); display.putc(0xFE); display.putc(0x53); } if(cfg>=4) //If config >=4, configuration end { reset_config(); } } } } } void reset_config(void) { led_cfg=0; //turn config led off cfg=0; //reset config variable mult = 10; //reset mult to standard value = 10 adj_ilimit(LCD_index+1,CH[LCD_index].limit); //adjust current limit new_cfg=1; save_cfg_time=t.read_ms(); display.putc(0xFE); display.putc(0x54); } //message incoming treatment - Socket EPICS void message_treatment(void) { ch_msg_idx = socket_buffer[0] - 0x30; //First character is the channel number if(ch_msg_idx>0 && ch_msg_idx<=8) //drop if out of range { ch_msg_idx--; //decrement to index 0 to 7 if(socket_buffer[1]=='r') //read message { n = sprintf(send_buffer,"OK>%d:\tV=%4.2f\tI=%3.2f\tC=%.1f\tIL=%3.2f\tF=%d\tOL=%d\tNL=%d\tE=%d\r\n",ch_msg_idx+1,\ CH[ch_msg_idx].voltage,CH[ch_msg_idx].current,\ CH[ch_msg_idx].control,CH[ch_msg_idx].limit,\ CH[ch_msg_idx].failure,CH[ch_msg_idx].overload>ERROR_REP,\ CH[ch_msg_idx].noload>ERROR_REP,CH[ch_msg_idx].enable); return; } if(socket_buffer[1]=='l') //current limit message { if(socket_buffer[2]=='?') //get { n = sprintf(send_buffer,"OK>%d:\tIL=%3.2f\r\n",ch_msg_idx+1,CH[ch_msg_idx].limit); return; } if(socket_buffer[3]=='.') //set (must be in 3.2f format) { ilimit_msg = (socket_buffer[2]-0x30) + (socket_buffer[4]-0x30)/10.0 + (socket_buffer[5]-0x30)/100.0; //convert three digits to float if(ilimit_msg > 0 && ilimit_msg <= CURR_MAX_LIMIT) //verifiy bounds { CH[ch_msg_idx].limit = ilimit_msg; ilimit_msg = ilimit_msg*I_K+I_OFF; //Convert to voltage do{ tx.data = int((0xFFF*ilimit_msg)/5)&0xFFF; //Convert to 12 bit data register_amc=DAC0+ch_msg_idx; //set register write_U4(); read_U4(); }while(tx.data!=rx.data); //try to write until success. (main thread also using SPI) n = sprintf(send_buffer,"OK>%d:\tIL=%3.2f\r\n",ch_msg_idx+1,CH[ch_msg_idx].limit); new_cfg=1; //new cfg file must be written by the main loop save_cfg_time = t.read_ms(); return; } else { n = sprintf(send_buffer,"ERROR>%5.2f out of range\r\n",ilimit_msg); return; } } } if(socket_buffer[1]=='e') //enable message { if(socket_buffer[2]=='?') //get method { n = sprintf(send_buffer,"OK>%d:\tE=%d\r\n",ch_msg_idx+1,CH[ch_msg_idx].enable); return; } if(socket_buffer[2]=='1') //set method (enable=1) { do{ register_amc = GPIO; //set GPIO register read_U5(); //read register tx.data = rx.data | (0b1<<ch_msg_idx); write_U5(); //write the 1 position read_U5(); }while(tx.data != rx.data); //try to write until success. (main thread also using SPI) CH[ch_msg_idx].enable = 1; new_cfg=1; save_cfg_time=t.read_ms(); n = sprintf(send_buffer,"OK>%d:\tE=%d\r\n",ch_msg_idx+1,CH[ch_msg_idx].enable); return; } if(socket_buffer[2]=='0') //set method (enable=0) - Disable { do{ register_amc = GPIO; //set GPIO register read_U5(); //read register tx.data = rx.data & ~(0b1<<ch_msg_idx); write_U5(); //write the 0 position read_U5(); }while(tx.data != rx.data); //try to write until success. (main thread also using SPI) CH[ch_msg_idx].enable = 0; new_cfg=1; save_cfg_time=t.read_ms(); n = sprintf(send_buffer,"OK>%d:\tE=%d\r\n",ch_msg_idx+1,CH[ch_msg_idx].enable); return; } } } if(socket_buffer[0]=='p'&&socket_buffer[1]=='i'&&socket_buffer[2]=='n'&&socket_buffer[3]=='g') //ping message { n = sprintf(send_buffer,"OK>pong\r\n"); //answer pong return; } if(socket_buffer[0]=='v') //firmware version { n = sprintf(send_buffer,"OK>firmware version = %s\r\n",VERSION); return; } if(socket_buffer[0]=='n') //device name { if(socket_buffer[1]=='?') { n = sprintf(send_buffer,"OK>device name = %s\r\n",dev_name); return; } if(socket_buffer[1]=='=') { n=0; while(socket_buffer[n+2]!='\0'&&n<=20) { dev_name[n]=socket_buffer[n+2]; n++; } dev_name[n]='\0'; new_cfg=1; save_cfg_time=t.read_ms(); n = sprintf(send_buffer,"OK>device name = %s\r\n",dev_name); return; } } if(socket_buffer[0]=='r'&&socket_buffer[1]=='e'&&socket_buffer[2]=='s'&&socket_buffer[3]=='e'&&socket_buffer[4]=='t') //reset messag { n = sprintf(send_buffer,"OK>rebooting...\r\n"); //answer client.send_all(send_buffer,n); wait_ms(500); mbed_reset(); //reset function return; } n = sprintf(send_buffer,"ERROR> NOT-A-CMD\r\n\0"); //command not found } void main_loop(void) //main thread (real-time priority) - read and write AMC devices { while(1){ if(flag_end_u5) //Wait U5 end of convertion { flag_end_u5 = 0; //Reset flag register_amc = ADC0; //reads U5 ADC0 fast_read_U5(); for(i=0;i<=7;i++) { register_amc = ADC0+i+1; //reads U5 ADC1 + i fast_read_U5(); CH[i].current = FILTC*CH[i].current + FILTC2*(((rx.data*5.0)/0xFFF)-I_OFF)/I_K; //store current of the previous channel if(CH[i].current<0) //negative current not allowed CH[i].current=0; } } if(flag_end_u4) //Wait U4 end of convertion { flag_end_u4 = 0; //Reset flag register_amc = ADC0; //reads U4 ADC0 fast_read_U4(); for(i=0;i<=7;i++) { register_amc = ADC8+i; //reads U4 ADC8 + i (ADC8 to ADC15) fast_read_U4(); CH[i].voltage = FILTC*CH[i].voltage+FILTC2*((rx.data*5.0)/0xFFF)/V_K; //store voltages (previous convertions - ADC0 to ADC7) if(CH[i].voltage<0) //negative voltage not allowed CH[i].voltage = 0; //Failure output triggered by NO LOAD or OVERLOAD //Determine overload via software (above 90% current limit) if(CH[i].current > CH[i].limit*0.85) { if(CH[i].overload<=2*ERROR_REP) //verify counter limit CH[i].overload++; //Increment overload counter if(CH[i].overload>=ERROR_REP) //Digital Filtering by repetitive overload diagnostics fail_out(i+1,1); //Set failure output } else { if(CH[i].overload>0) CH[i].overload--; //decrement overload counter if(CH[i].overload<ERROR_REP) //verify overload condition if(CH[i].noload<ERROR_REP) //verify no load condition fail_out(i+1,0); //Reset failure output } //Determine no load via software (Resistance over 150 ohm) if(CH[i].voltage > 2 && CH[i].current < CH[i].voltage/150) { if(CH[i].noload<=2*ERROR_REP) //verify counter limit CH[i].noload++; //Increment no load counter if(CH[i].noload>=ERROR_REP) //Digital Filtering by repetitive no load diagnostics fail_out(i+1,1); //Set failure output } else { if(CH[i].noload>0) CH[i].noload--; //decrement no load counter if(CH[i].noload<ERROR_REP) //verify no load condition if(CH[i].overload<ERROR_REP) //verify overload condition fail_out(i+1,0); //Reset failure output } register_amc = ADC0+i+1; //Read next ADC (ADC0 to ADC7) fast_read_U4(); //Estimate control input (Duty cycle in %) CH[i].control = FILTC*CH[i].control+FILTC2*(rx.data*VC_K*5.0/0xFFF+VC_OFF); #ifndef CAL //Verify limits if(CH[i].control<0) CH[i].control=0; if(CH[i].control>100) CH[i].control=100; #endif } DEBUG_PRINTF("Duty Cycle Calibration - Measured Voltage: %f",rx.data*5.0/0xFFF); } } } //initiate socket instances void socket_start() { server.set_blocking(true); // Set socket connection not blocking client.set_blocking(false,50); server.bind(PORT); // TCP Socket setup server.listen(2); // Socket Server start listening request. } //Server loop (thread triggered) void server_loop(void) { while(1) { httpsvr.run(&CH[0],dev_name); //wait for new client connection server_led = !server_led; //togle server led } } //Socket loop (thread triggered) - for EPICS void socket_loop(void) { while(1) { socket_led = !socket_led; //toggle socket LED if(server.accept(client)!=-1) //blocks waiting for a new client { client.set_blocking(false,50); // Set client connection not blocking while(client.is_connected()) // while connected { socket_led = !socket_led; //toggle LED again (fast flash) receive_return = client.receive_all(socket_buffer,200); //receive all messages if(receive_return>0) //if bytes received { message_treatment(); //treat message client.send_all(send_buffer,n); //send answer } if(receive_return < 0) //if erro, break connection break; } client.close(); //finally close the client } } } //AMC7812B setup (U4 and U5) void amc_setup(void){ cs_u4 = 1; //Chip Select must be deselected cs_u5 = 1; //Chip Select must be deselected dac_clr = 1; //DAC Clear inactive amc_reset = 1; //Reset Inactive cnvt_u5 = 1; //U5 Convertion not triggered cnvt_u4 = 1; //U4 Convertion not triggered //Reset AMC7812B to make sure both are in the initial state amc_reset = 0; wait_ms(5); amc_reset = 1; // Setup the spi for 12 bit data, high steady state clock, // second edge capture, with a 10MHz clock rate spi.format(12,1); spi.frequency(10000000); wait_ms(10); //Wait AMC7812B power up //Disabling Power Down Register tx.data = 0x7FFE; register_amc = PWR_DOWN; write_U4(); write_U5(); //Set all ADC range 0 to 5V tx.data = 0xFFFF; register_amc = ADC_GAIN; write_U4(); write_U5(); //Set all u4 16 ADC channels active register_amc = ADC_CH0; tx.data = 0x6DFF; write_U4(); register_amc = ADC_CH1; tx.data = 0x7000; write_U4(); //Set u5 first 8 ADC channels active tx.data = 0x6DE0; register_amc = ADC_CH0; write_U5(); //Disable LT, D1 and D2 tx.data = 0x0000; register_amc = T_CONF; write_U4(); write_U5(); tx.data = 0x0400; //Set both in direct mode //tx.data = 0x2400; //Set both in auto mode register_amc = CONF0; write_U4(); write_U5(); tx.data = 0x0300; //Set convertion ate to 62.5kS/s (auto mode) register_amc = CONF1; write_U4(); write_U5(); } //Adjust current limit // // Parameters: // - int channel: channel to adjust (from 1 to 8) // - float value: current value // void adj_ilimit(int channel,float value) //channel from 1 to 8 { if(value > CURR_MAX_LIMIT) //current allowed up to CURR_MAX_LIMIT value = CURR_MAX_LIMIT; value = value*I_K+I_OFF; //Convert to voltage tx.data = int((0xFFF*value)/5)&0xFFF; //Convert to 12 bit data register_amc=DAC0+channel-1; //set register write_U4(); //write U4 AMC7812B DAC } //Set/Reset Failure Output // // Parameters: // - int channel: channel to adjust (from 1 to 8) // - int value: output 5V (value=1) or 0V (value=0) // void fail_out(int channel,int value)//channel from 1 to 8 { tx.data = 0xFFF*value; //set 12bit data to DAC register_amc=DAC0+channel-1; //set register write_U5(); //write U5 AMC7812B CH[channel-1].failure = value; //update data structure } //U4 end of convertion Interrupt void end_conv_u4(void){ flag_end_u4 = 1; //set U4 flag } //U5 end of convertion Interrupt void end_conv_u5(void){ flag_end_u5 = 1; //set U5 flag } //Trigger Both (U4 and U5) AD convertions void trigger_conv(void){ //Triggering ADC via software - Setting flag ICONV inside CONF register /* register_amc = CONF0; read_U4(); tx.data = rx.data | 0x1000; write_U4(); read_U5(); tx.data = rx.data | 0x1000; write_U5(); */ //Triggering ADC via hardware - CONV pin active low. cnvt_u5 = 0; cnvt_u4 = 0; cnvt_u5 = 1; cnvt_u4 = 1; } //Trigger U4 convertion void trigger_u4(void) { cnvt_u4 = 0; cnvt_u4 = 1; } //Trigger U5 convertion void trigger_u5(void) { cnvt_u5 = 0; cnvt_u5 = 1; } //U5 Fast Read Function //fast_read saves always the previous read value in rx.data //See AMC7812B datasheet for more details void fast_read_U5(void){ cs_u5 = 0; // Select the device by seting chip select low reg_aux = spi.write((register_amc|0x80)<<4); rx.data = (reg_aux&0xF)<<12; reg_aux = spi.write(0x000); rx.data = rx.data|(reg_aux&0xFFF); cs_u5 = 1; // Deselect the device by seting chip select low } //U4 Fast Read Function //fast_read saves always the previous read value in rx.data //See AMC7812B datasheet for more details void fast_read_U4(void){ cs_u4 = 0; // Select the device by seting chip select low reg_aux = spi.write((register_amc|0x80)<<4); rx.data = (reg_aux&0xF)<<12; reg_aux = spi.write(0x000); rx.data = rx.data|(reg_aux&0xFFF); cs_u4 = 1; // Deselect the device by seting chip select low } //U5 SPI read function //Read two times to assure the second read will save the first read result in rx.data //Takes about two times the fast_read function void read_U5(void){ cs_u5 = 0; // Select the device by seting chip select low spi.write((register_amc|0x80)<<4); spi.write(0x000); cs_u5 = 1; // Deselect the device by seting chip select low cs_u5 = 0; // Select the device by seting chip select low reg_aux = spi.write((register_amc|0x80)<<4); rx.data = (reg_aux&0xF)<<12; reg_aux = spi.write(0x000); rx.data = rx.data|(reg_aux&0xFFF); cs_u5 = 1; // Deselect the device by seting chip select low } //U4 SPI read function //Read two times to assure the second read will save the first read result in rx.data //Takes about two times the fast_read function void read_U4(void){ cs_u4 = 0; // Select the device by seting chip select low spi.write((register_amc|0x80)<<4); spi.write(0x000); cs_u4 = 1; // Deselect the device by seting chip select low cs_u4 = 0; // Select the device by seting chip select low reg_aux = spi.write((register_amc|0x80)<<4); rx.data = (reg_aux&0xF)<<12; reg_aux = spi.write(0x000); rx.data = rx.data|(reg_aux&0xFFF); cs_u4 = 1; // Deselect the device by seting chip select low } //U4 SPI write function void write_U4(void){ cs_u4 = 0; // Select the device by seting chip select low reg_aux = register_amc<<4|((tx.data&0xF000)>>12); spi.write(reg_aux); spi.write(tx.data&0xFFF); cs_u4 = 1; // Deselect the device by seting chip select low } //U5 SPI write function void write_U5(void){ cs_u5 = 0; // Select the device by seting chip select low reg_aux = register_amc<<4|((tx.data&0xF000)>>12); spi.write(reg_aux); spi.write(tx.data&0xFFF); cs_u5 = 1; // Deselect the device by seting chip select low } //Initialize variables and LCD void setup(){ //Auxiliary variables int aux; char c; float tmp_lim; int tmp_en; uint8_t gpio_init=0; phy_rst = 0; //reset ethernet Phy eth_led1 = 0; //turn off ethernet led 1 eth_led2 = 0; //turn off ethernet led 2 phy_rst = 1; //Power on ethernet Phy display.baud(19200); //Clear all display LEDs display.putc(0xFE); display.putc(0x5A); display.putc(0x00); display.putc(0x00); display.putc(0xFE); display.putc(0x5A); display.putc(0x01); display.putc(0x00); display.putc(0xFE); display.putc(0x5A); display.putc(0x02); display.putc(0x00); //Set display contrast display.putc(0xFE); display.putc(0x91); display.putc(0x80); //Config file handler cfg_file = fopen("/local/lim.cfg", "r"); // Open "lim.cfg" on the local file system for reading if(cfg_file==NULL) //If config file doesnt exist, create new file { cfg_file = fopen("/local/lim.cfg", "w"); //Open "lim.cfg" on the local file system for writing fprintf(cfg_file,"Channel Configuration - Current Limit and Enable\n"); fprintf(cfg_file,"%s\n",DEVICE_NAME); strcpy(dev_name,DEVICE_NAME); for(i=0;i<8;i++) { CH[i].limit = DEFAULT_CURR_LIMIT; //Save default current limit in all channels fprintf(cfg_file,"%d %3.2f 1\n",i+1,DEFAULT_CURR_LIMIT); //Write to file CH[i].enable = 1; } ERROR_PRINTF("lim.cfg file not found! Creating default file..."); } else //File exists :) { do{ c = getc(cfg_file); }while(c!='\n'); //Linescan (scan until \n) fscanf(cfg_file,"%s",dev_name); //Read name string for(i=0;i<8;i++) //Read 8 channels { fscanf(cfg_file,"%d %f %d",&aux,&tmp_lim,&tmp_en); //Read channel and limit value if(tmp_lim<0||tmp_lim>CURR_MAX_LIMIT) //Verify limits tmp_lim=DEFAULT_CURR_LIMIT; //If tmp is above limit, use default CH[i].limit = tmp_lim; //set channel limit CH[i].enable = tmp_en&0x1; } } fclose(cfg_file); //close config file gpio_init=0; for(i=0;i<8;i++) //set structure variables { CH[i].noload = 0; //no load variable CH[i].overload = 0; //oveload variable fail_out(i+1,0); //reset failure output adj_ilimit(i+1,CH[i].limit); //adjust current limit gpio_init = gpio_init | (CH[i].enable&0x1)<<i; } write_LCD(); //write to LCD reset_config(); //reset configuration flag_end_u4=0; //reset U4 end of convertion flag flag_end_u5=0; //reset U5 end of convertion flag //set GPIO aoutput high (enable) tx.data = gpio_init; //enable all channels (hardware GPIO) register_amc = GPIO; write_U5(); } //Clear LCD Function void clear_lcd(){ display.putc(0xFE); display.putc(0x58); } //Set Red Led - Error void error(){ display.putc(0xFE); display.putc(0x5A); display.putc(0x00); display.putc(0x02); } //Set Green Led - Normal void normal(){ display.putc(0xFE); display.putc(0x5A); display.putc(0x00); display.putc(0x01); } //Set Red and Green - Disabled void disabled(){ display.putc(0xFE); display.putc(0x5A); display.putc(0x00); display.putc(0x03); } //Write channel index to LCD void write_LCD() { if(CH[LCD_index].failure == 1) error(); //error status if failure else { if(CH[LCD_index].enable == 0) disabled(); //disabled status if not enabled else normal(); //Normal mode } clear_lcd(); //Clear LCD display.printf("CH%d %5.2fV/%3.2fAC:%03.0f%% IL:%3.2fA",LCD_index+1,CH[LCD_index].voltage,CH[LCD_index].current,CH[LCD_index].control,CH[LCD_index].limit); } //Heartbeat toogle MBED led function void heart(){ blink = !blink; //toggle blink led }