/********************************************************************\ Name: fe_cc.c Created by: Stefan Ritt Contents: Firmware for Mu3e Front End Crate Controller using a SiLabs C8051F120 CPU \********************************************************************/ #include #include #include #include #include "mscbemb.h" #include "DS28EA00.h" #include "fe_cc.h" sbit CS8900A_RESET = P0 ^ 5; sbit RS485_ENABLE = RS485_EN_PIN; sbit STATUS_OK = P5 ^ 4; bit submaster_configured; bit client_configured; bit flash_client; // used for EEPROM flashing bit flash_program; // used for firmware upgrade bit mem_command; // used for read/write memory commands USER_DATA user_data; CLI_CFG cli_cfg; extern void process_mem_command(void); MSCB_INFO_VAR code vars[] = { { 1, UNIT_BYTE, 0, 0, 0, "Status", &user_data.status }, // 0 { 4, UNIT_VOLT, 0, 0, MSCBF_FLOAT, "U24", &user_data.voltage[0] }, // 1 { 4, UNIT_VOLT, 0, 0, MSCBF_FLOAT, "U3.3", &user_data.voltage[1] }, // 2 { 4, UNIT_VOLT, 0, 0, MSCBF_FLOAT, "U5.0", &user_data.voltage[2] }, // 3 { 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "Temp", &user_data.temp }, // 4 { 1, UNIT_BOOLEAN, 0, 0, 0, "FEB00", &user_data.board_power[0] }, // 5 { 1, UNIT_BOOLEAN, 0, 0, 0, "FEB01", &user_data.board_power[1] }, // 6 { 1, UNIT_BOOLEAN, 0, 0, 0, "FEB02", &user_data.board_power[2] }, { 1, UNIT_BOOLEAN, 0, 0, 0, "FEB03", &user_data.board_power[3] }, { 1, UNIT_BOOLEAN, 0, 0, 0, "FEB04", &user_data.board_power[4] }, { 1, UNIT_BOOLEAN, 0, 0, 0, "FEB05", &user_data.board_power[5] }, { 1, UNIT_BOOLEAN, 0, 0, 0, "FEB06", &user_data.board_power[6] }, { 1, UNIT_BOOLEAN, 0, 0, 0, "FEB07", &user_data.board_power[7] }, { 1, UNIT_BOOLEAN, 0, 0, 0, "FEB08", &user_data.board_power[8] }, { 1, UNIT_BOOLEAN, 0, 0, 0, "FEB09", &user_data.board_power[9] }, { 1, UNIT_BOOLEAN, 0, 0, 0, "FEB10", &user_data.board_power[10] }, { 1, UNIT_BOOLEAN, 0, 0, 0, "FEB11", &user_data.board_power[11] }, { 1, UNIT_BOOLEAN, 0, 0, 0, "FEB12", &user_data.board_power[12] }, { 1, UNIT_BOOLEAN, 0, 0, 0, "FEB13", &user_data.board_power[13] }, { 1, UNIT_BOOLEAN, 0, 0, 0, "FEB14", &user_data.board_power[14] }, { 1, UNIT_BOOLEAN, 0, 0, 0, "FEB15", &user_data.board_power[15] }, // 20 { 1, UNIT_BOOLEAN, 0, 0, 0, "Maxcfg", &user_data.max_config }, // 21 { 1, UNIT_BOOLEAN, 0, 0, MSCBF_DATALESS, "RstFPGA", 0 }, // 22 { 1, UNIT_BOOLEAN, 0, 0, MSCBF_DATALESS, "RstCPU", 0 }, // 23 { 1, UNIT_BOOLEAN, 0, 0, MSCBF_DATALESS, "RstMAX", 0 }, // 24 { 1, UNIT_BYTE, 0, 0, 0, "BPMode", &user_data.bp_mode_sel }, // 25 { 1, UNIT_BYTE, 0, 0, 0, "Attn", &user_data.attention }, // 26 { 1, UNIT_ASCII, 0, 0, MSCBF_DATALESS, "SPI", 0 }, // 27 { 1, UNIT_BYTE, 0, 0, 0, "SPI_SLT", &user_data.spi_slot }, // 28 { 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "1WTemp00", &user_data.ow_temp[0] }, // 29 { 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "1WTemp01", &user_data.ow_temp[1] }, { 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "1WTemp02", &user_data.ow_temp[2] }, { 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "1WTemp03", &user_data.ow_temp[3] }, { 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "1WTemp04", &user_data.ow_temp[4] }, { 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "1WTemp05", &user_data.ow_temp[5] }, { 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "1WTemp06", &user_data.ow_temp[6] }, { 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "1WTemp07", &user_data.ow_temp[7] }, { 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "1WTemp08", &user_data.ow_temp[8] }, { 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "1WTemp09", &user_data.ow_temp[9] }, { 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "1WTemp10", &user_data.ow_temp[10] }, { 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "1WTemp11", &user_data.ow_temp[11] }, { 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "1WTemp12", &user_data.ow_temp[12] }, { 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "1WTemp13", &user_data.ow_temp[13] }, { 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "1WTemp14", &user_data.ow_temp[14] }, { 4, UNIT_CELSIUS, 0, 0, MSCBF_FLOAT, "1WTemp15", &user_data.ow_temp[15] }, { 8, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "1WAdr00", &user_data.ow_adr[0] }, // 45 { 8, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "1WAdr01", &user_data.ow_adr[1] }, { 8, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "1WAdr01", &user_data.ow_adr[2] }, { 8, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "1WAdr01", &user_data.ow_adr[3] }, { 8, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "1WAdr01", &user_data.ow_adr[4] }, { 8, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "1WAdr01", &user_data.ow_adr[5] }, { 8, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "1WAdr01", &user_data.ow_adr[6] }, { 8, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "1WAdr01", &user_data.ow_adr[7] }, { 8, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "1WAdr01", &user_data.ow_adr[8] }, { 8, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "1WAdr01", &user_data.ow_adr[9] }, { 8, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "1WAdr01", &user_data.ow_adr[10] }, { 8, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "1WAdr01", &user_data.ow_adr[11] }, { 8, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "1WAdr01", &user_data.ow_adr[12] }, { 8, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "1WAdr01", &user_data.ow_adr[13] }, { 8, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "1WAdr01", &user_data.ow_adr[14] }, { 8, UNIT_BYTE, 0, 0, MSCBF_HIDDEN, "1WAdr01", &user_data.ow_adr[15] }, { 0 } }; MSCB_INFO_VAR *variables = vars; unsigned char xdata update_data[64]; unsigned long xdata start_time; unsigned char xdata spi_tx_buf[64]; unsigned char xdata spi_tx_n; #define SPI_RX_SIZE 64 unsigned char xdata spi_rx_buf[SPI_RX_SIZE]; unsigned char xdata spi_rx_wp; unsigned char xdata spi_rx_rp; void user_write(unsigned char index, unsigned char *buf) reentrant; void user_update(void); unsigned long int last_1wire_read; /*------------------------------------------------------------------*/ void setup(void) { unsigned short i; // software timer watchdog_disable(); // Disable watchdog timer SFRPAGE = CONFIG_PAGE; // set SFR page XBR0 = 0x04; // Enable UART0 XBR1 = 0x00; XBR2 = 0x40; // all pins used by the external memory interface are in push-pull mode P0MDOUT = 0xFF; P1MDOUT = 0xFF; P2MDOUT = 0xFF; P3MDOUT = 0xFF; P5MDOUT = 0xDE; // P5.0, P5.5 input (MISO, 1-wire) P6MDOUT = 0x7F; // P6.7 (BACKPLANE_DI) is input P0 = 0xE0; // /WR, /RD, are high, RESET is high P1 = 0x00; P2 = 0x00; // P1, P2 contain the address lines P3 = 0xFF; // P3 contains the data lines P5 = 0xFF; P6 = 0xFF; OSCICN = 0x83; // set internal oscillator to run // at its maximum frequency CLKSEL = 0x00; // Select the internal osc. as // the SYSCLK source //Turn on the PLL and increase the system clock by a factor of M/N = 2 PLL0CN = 0x00; // Set internal osc. as PLL source SFRPAGE = LEGACY_PAGE; FLSCL = 0x10; // Set FLASH read time for 50MHz clk or less SFRPAGE = CONFIG_PAGE; PLL0CN |= 0x01; // Enable Power to PLL PLL0DIV = 0x01; // Set Pre-divide value to N (N = 1) PLL0FLT = 0x01; // Set the PLL filter register for // a reference clock from 19 - 30 MHz // and an output clock from 45 - 80 MHz PLL0MUL = 0x02; // Multiply SYSCLK by M (M = 2) for (i = 0; i < 256; i++); // Wait at least 5us PLL0CN |= 0x02; // Enable the PLL // Wait until PLL frequency is locked for (i = 0 ; i<50000 && ((PLL0CN & 0x10) == 0) ; i++); CLKSEL = 0x02; // Select PLL as SYSCLK source SFRPAGE = LEGACY_PAGE; EMI0CF = 0xD7; // Split-Mode, non-multiplexed // on P0-P3 (use 0xF7 for P4 - P7) EMI0TC = 0xB7; // This value may be modified // according to SYSCLK to meet the // timing requirements for the CS8900A // For example, EMI0TC should be >= 0xB7 // for a 100 MHz SYSCLK. /* init memory */ RS485_ENABLE = 0; /* remove reset from CS8900A chip */ delay_ms(10); CS8900A_RESET = 0; /* initialize UART0 */ uart_init(0, BD_115200); PS0 = 1; // serial interrupt high priority /* reset system clock */ sysclock_reset(); /* Blink LEDs */ led_blink(0, 3, 150); led_blink(1, 3, 150); } /*---- User init function ------------------------------------------*/ void user_init(unsigned char init) { unsigned char i, j; if (init) { for (i=0 ; i<27 ; i++) user_data.board_power[i] = 0; user_data.max_config = 0; user_data.bp_mode_sel = 0; user_data.attention = 0; } user_data.status = 1; user_data.spi_slot = 0; spi_init(); gpio_init(); monitor_init(); gpio_board_power(user_data.board_power); // backplane SPI always active (single master) backplane_spi_cs(0); // init 1-wire data for (i=0 ; i<16 ; i++) { user_data.ow_temp[i] = -999; for (j=0 ; j<8 ; j++) user_data.ow_adr[i][j] = 0; } for (i=0 ; i<16 ; i++) { gpio_board_select(i); DS28EA00_scan(i); gpio_board_select(0xFF); } last_1wire_read = 0; // set status output user_write(0, NULL); spi_rx_wp = spi_rx_rp = 0; } /*---- User write function -----------------------------------------*/ void user_write(unsigned char index, unsigned char *buf) reentrant { unsigned char n, ofs; if (index == 0) { STATUS_OK = user_data.status; } if (index == 27) { // write data to SPI bus via spi_tx_buf n = buf[0] & 0x07; ofs = 2; if (n == 0x07) { // variable length n = buf[1]; ofs = 3; } n--; // skip channel memcpy(spi_tx_buf, buf+ofs, n); spi_tx_n = n; } update_data[index] = 1; } /*---- User read function -----------------------------------------*/ unsigned char user_read(unsigned char index, unsigned char *buf) reentrant { unsigned short i; if (index == 22 || index == 23 || index == 24) { buf[0] = 0; return 1; } if (index == 27) { for (i = 0 ; i<256 && spi_rx_wp != spi_rx_rp ; i++) { buf[i] = spi_rx_buf[spi_rx_rp]; spi_rx_rp = (spi_rx_rp+1) % SPI_RX_SIZE; } return i; } return 0; } /*------------------------------------------------------------------*/ void user_update(void) { unsigned char i; for (i=0 ; i<16 ; i++) { if (update_data[5+i]) { gpio_board_power(user_data.board_power); update_data[5+i] = 0; } } if (update_data[21]) { gpio_max_config_select(user_data.max_config); update_data[21] = 0; } if (update_data[22]) { gpio_reset_fpga(); update_data[22] = 0; } if (update_data[23]) { gpio_reset_cpu(); update_data[23] = 0; } if (update_data[24]) { gpio_reset_max(); update_data[24] = 0; } if (update_data[25]) { gpio_bp_mode_sel(user_data.bp_mode_sel); update_data[25] = 0; } if (update_data[26]) { gpio_attention(user_data.attention); update_data[26] = 0; } if (update_data[27]) { gpio_board_select(user_data.spi_slot); for (i = 0; i < spi_tx_n; i++) backplane_spi_write_msb(spi_tx_buf[i]); gpio_board_select(0xFF); update_data[27] = 0; } for (i = 0 ; i<16 ; i++) { if (update_data[45+i]) { if (user_data.ow_adr[i][0] == 1) { // get ROM address for slot "i" // board select works as PIOB for DS28EA00 gpio_board_select(i); DS28EA00_scan(i); gpio_board_select(0xFF); led_blink(0, 5, 100); } update_data[45+i] = 0; } } if (update_data[46]) { if (user_data.ow_adr[1][0] == 0) { DS28EA00_scan(1); led_blink(0, 5, 100); } update_data[46] = 0; } } /*------------------------------------------------------------------*/ void spi_poll() { if (spi_rx_rp == spi_rx_wp) { spi_rx_buf[spi_rx_wp] = 'X'; spi_rx_wp = (spi_rx_wp+1) % SPI_RX_SIZE; } } /*------------------------------------------------------------------*/ unsigned char flash_read_data(void) { unsigned char code *p_flash; memset(&cli_cfg, 0, sizeof(cli_cfg)); memset(&user_data, 0, sizeof(user_data)); SFRPAGE = LEGACY_PAGE; p_flash = 0x80; // second sector PSCTL = 0x04; // select scratchpad area memcpy(&cli_cfg, p_flash, sizeof(cli_cfg)); p_flash = 0x80 + sizeof(cli_cfg); memcpy(&user_data, p_flash, sizeof(user_data)); PSCTL = 0x00; // unselect scratchpad area if (cli_cfg.magic != 0x1234) { cli_cfg.node_addr = 0xFFFF; cli_cfg.group_addr = 0xFFFF; strcpy(cli_cfg.node_name, "FE_CC"); cli_cfg.magic = 0x1234; return 1; } else client_configured = 1; return 0; } /*------------------------------------------------------------------*/ void flash_write_client_data(void) { // pointer has to reside in idata, otherwise it will conflict // with the flash access in XDATA unsigned char xdata * idata p_flash; /* Disable watchdog timer */ watchdog_disable(); DISABLE_INTERRUPTS; SFRPAGE = LEGACY_PAGE; /* erase scratchpad area */ p_flash = 0x80; // second sector FLSCL = FLSCL | 1; // enable flash writes/erases PSCTL = 0x07; // allow write and erase to scratchpad area *((char *)p_flash) = 0; // erase page PSCTL = 0x05; // allow write to scratchpad area p_flash = 0x80; memcpy(p_flash, &cli_cfg, sizeof(cli_cfg)); p_flash = 0x80 + sizeof(cli_cfg); memcpy(p_flash, &user_data, sizeof(user_data)+4); // odd bytes will not be flashed FLSCL = FLSCL & ~1; // disable flash writes/erases PSCTL = 0; // disable flash access ENABLE_INTERRUPTS; watchdog_enable(10); } /*------------------------------------------------------------------*/ void measure() { static unsigned long last = 0; // only do ten times per second if (time() - last < 10) return; last = time(); /*---- monitor voltage and currents ----*/ user_data.voltage[0] = monitor_read_adc(MON_24V); user_data.voltage[1] = monitor_read_adc(MON_3_3V); user_data.voltage[2] = monitor_read_adc(MON_5V); /*---- read temperatures ----*/ user_data.temp = monitor_read_adc(MON_TEMP); } /*------------------------------------------------------------------*/ void main(void) { unsigned char i, start; SFRPAGE = 0; RSTSRC = 0x02; // Select VddMon as a reset source for (i=100 ; i>0 ; i--); // Wait for VDD stabilized // initialize the C8051F12x setup(); // get user data from flash flash_client = 0; flash_program = 0; mem_command = 0; i = flash_read_data(); // initialize drivers user_init(i); // initialize submaster submaster_init(); // turn on watchdog watchdog_enable(10); // remembr startup start = 1; #ifndef HAVE_ETHERNET led_mode(0, 1); led_set(0, LED_OFF); #endif do { #ifdef HAVE_ETHERNET if (!client_configured || !submaster_configured) led_blink(0, 1, 50); #else if (!client_configured) led_blink(0, 1, 50); #endif if (flash_client) { flash_client = 0; flash_write_client_data(); client_configured = 1; flash_read_data(); } if (flash_program) { flash_program = 0; /* wait until acknowledge has been sent */ delay_ms(10); /* go to "bootloader" program */ upgrade(); } if (mem_command) { process_mem_command(); mem_command = 0; } // turn on power earliest 5 seconds after power-up if (start && uptime() >= 5) { start = 0; update_data[0] = 1; user_update(); } watchdog_refresh(0); #ifdef HAVE_ETHERNET submaster_yield(); #endif measure(); user_update(); spi_poll(); // measure 1-wire once per 10 seconds if (time() > last_1wire_read + 1000) { last_1wire_read = time(); DS28EA00_read(user_data.ow_temp); led_blink(0, 1, 100); } } while (1); }