/* returns 1 if the id was expected and set, 0 otherwise */ static void set_node_id(unsigned char id) { TIMER_ID_INPUT = UINT_MAX; if(flash_write_byte((unsigned char *) NODE_ID_LOCATION, id) != 0) { flash_erase_segment((unsigned int *) NODE_ID_LOCATION); flash_write_byte((unsigned char *) NODE_ID_LOCATION, id); } node_id = id; printf("this node id is now 0x%02X\r\n", id); }
void blackbox_write(uchar type, const char* data, uchar length) { uint32_t tick = clock_tics; // Get number of ticks (this might change during writing, so we need a local copy) flash_write_byte(BLACKBOX_FRAME_START); // Write start byte flash_write_byte(type); // Write type flash_write_byte(tick >> 24); // Write tick flash_write_byte(tick >> 16); // flash_write_byte(tick >> 8); // flash_write_byte(tick); // flash_write_byte(length); // Write length flash_write(data, length); // Write data flash_write_byte(BLACKBOX_FRAME_END); // Write end byte }
/** * @fn static void eeprom_format_page(U16 phy_addr) * @brief erase page and write erase count plus 1 in TAG position. * for erase count equal 0xFFFFFF, plus '1' will get 0x1000000, and will only * write 24 bits 0x000000 into flash. * @param phy_addr physical page address * * @return none */ static void eeprom_format_page(U16 phy_addr) { UU32 erase_count; /* Ignore first byte in page, it is flash status byte*/ erase_count.U8[0] = 0; erase_count.U8[1] = flash_read_byte(phy_addr + 1); erase_count.U8[2] = flash_read_byte(phy_addr + 2); erase_count.U8[3] = flash_read_byte(phy_addr + 3); erase_count.U32 += 1; flash_erase_page(phy_addr); flash_write_byte(phy_addr + 1, erase_count.U8[1]); flash_write_byte(phy_addr + 2, erase_count.U8[2]); flash_write_byte(phy_addr + 3, erase_count.U8[3]); }
/* * write a command, consisting of 8 cmd bits, and 24 address bits. */ static void flash_write_cmd( uint8_t cmd, uint32_t addr ) { cs_low( ); flash_write_byte( cmd ); flash_write_byte( addr >> 24 ); flash_write_byte( addr >> 16 ); flash_write_byte( addr >> 8 ); }
/* * read the Flash status byte */ static uint8_t flash_read_status( void ) { uint8_t status; cs_low( ); flash_write_byte( AT_STATUS ); status = flash_read_byte( ); cs_high( ); return status; }
U8 eeprom_write_byte(U8 log_addr, U8 byte) { U16 phy_addr; if (log_addr >= EE_SIZE) return ERROR; /* The page is full, we need to find a new page*/ if(page.tail >= FL_PAGE_SIZE) { phy_addr = eeprom_get_next_page(page.idx) + EE_TAG_SIZE; flash_write_byte(phy_addr, log_addr); flash_write_byte(phy_addr + 1, byte); flash_copy_page(); }else{ phy_addr = page.addr + page.tail; flash_write_byte(phy_addr, log_addr); flash_write_byte(phy_addr + 1, byte); page.tail += EE_VARIABLE_SIZE; } return SUCCESS; }
/** * @fn void flash_copy_page() * @brief move valid data from one page to another page. * * When an active page is full, it will find next available page, and write data * in it, and then call this function. It copies data from source page to * destination page. * * @note When calling this function, be aware that destination page already write * a pair of the data. Before copy loop start, we need to read it out and set * bitmap correspond bit to '1'. * * @return none */ static void flash_copy_page() { U16 src, dest, tail; U8 log_addr,idx; U8 eeprom_bitmap[EE_BITMAP_SIZE]; for (idx = 0; idx < EE_BITMAP_SIZE; idx++) { eeprom_bitmap[idx] = 0; } /* Source page scan start from bottom*/ src = page.addr + FL_PAGE_SIZE - EE_VARIABLE_SIZE; dest = eeprom_get_next_page(page.idx); /* Mark destination page as receiving status */ flash_write_byte(dest,PAGE_STATUS_RECEIVING); EE_SET_BITMAP(flash_read_byte(dest + EE_TAG_SIZE)); tail =EE_TAG_SIZE + EE_VARIABLE_SIZE; /* Read data from source page and copy it to destination page*/ while (src >= (page.addr + EE_TAG_SIZE)) { log_addr = flash_read_byte(src); if (log_addr < EE_SIZE) { if (!EE_GET_BITMAP(log_addr)) { flash_write_byte(dest + tail, log_addr); flash_write_byte(dest + tail + 1, flash_read_byte(src + 1)); tail += EE_VARIABLE_SIZE; EE_SET_BITMAP(log_addr); } } src -= EE_VARIABLE_SIZE; } /* Mark destination page as active status*/ flash_write_byte(dest,PAGE_STATUS_ACTIVE); /* Erase source page and update erase count in page TAG position*/ eeprom_format_page(page.addr); /* Update page information*/ idx = (dest - EE_BASE_ADDR) / FL_PAGE_SIZE; eeprom_update_page_info(idx, dest, tail); }
char flash_write(short size, int offset, uint32 value){ switch(size){ case 8: flash_write_byte (offset, value); break; case 16: flash_write_halfword(offset, value); break; case 32: flash_write_word(offset, value); break; default: return -1; } return 0; }
/** * @fn static void eeprom_check_pages(void) * @brief Check page status, handle different page status. * * The first byte of flash page is status byte. It contains three status: * RECEIVING, ACTIVE, ERASED. We will format RECEIVING page; if ERASED page * is not blank, we will format it too. If we have two more ACTIVE pages, * we will erase full one * * @return none */ static void eeprom_check_pages(void) { U8 i, status, idx, active_pages = 0; U16 phy_addr ,active_page_addr = EE_BASE_ADDR; for (i = 0; i < FL_PAGES; i++) { phy_addr = EE_BASE_ADDR + i * FL_PAGE_SIZE; status = flash_read_byte(phy_addr); switch (status) { case PAGE_STATUS_RECEIVING: eeprom_format_page(phy_addr); break; case PAGE_STATUS_ERASED: if (!eeprom_is_formatted(phy_addr)) eeprom_format_page(phy_addr); break; case PAGE_STATUS_ACTIVE: if (active_pages++) { U16 tmp = phy_addr + FL_PAGE_SIZE - EE_VARIABLE_SIZE; /* erase a full contents page*/ if (flash_read_byte(tmp) == 0xFF) { eeprom_format_page(phy_addr); }else{ eeprom_format_page(active_page_addr); active_page_addr = phy_addr; idx = i; } }else{ active_page_addr = phy_addr; idx = i; } break; default: break; } } /* If there is no active page, we update page status position with active status flag*/ if (0 == active_pages) flash_write_byte(active_page_addr,PAGE_STATUS_ACTIVE); eeprom_scan_page(active_page_addr,idx); }
void blackbox_write_adc(const uint16_t *data) { uint32_t tick = clock_tics; // Get number of ticks (this might change during writing, so we need a local copy) flash_write_byte(BLACKBOX_FRAME_START); // Write start byte flash_write_byte(BLACKBOX_FRAME_TYPE_ADC); // Write type flash_write_byte(tick >> 24); // Write tick flash_write_byte(tick >> 16); // flash_write_byte(tick >> 8); // flash_write_byte(tick); // flash_write_byte(ADC_NUM_CHANNELS*2); // Write length for (uchar i=0; i<ADC_NUM_CHANNELS; i++) { flash_write_byte(data[i] >> 8); // Write high byte flash_write_byte(data[i]); // Write low byte } flash_write_byte(BLACKBOX_FRAME_END); // Write end byte //blackbox_write(BLACKBOX_FRAME_TYPE_ADC, (char *)adc_values, sizeof(uint16_t) * ADC_NUM_CHANNELS); }
/* Ma-ma-ma-main function! */ void main() { command_t cmd = CMD_NO_CMD; uint16_t channel_timer = 0, bootloader_timer = 0, connection_timer = 0; uint8_t ch_i = 0; bool running; // Disable global interrupt cli(); // Set up parameters for RF communication. configureRF(); #ifdef DEBUG_LED_ P0DIR = 0; P0 = 0x55; #endif running = true; // Boot loader loop. // Will terminate after a couple of seconds if firmware has been successfully // installed. send(CMD_PING,1); while(running) { if(send_success){ if (packet_received) { connection_timer = 0; cmd = MSG_CMD; switch (cmd) { // Host initiates contact with the device. case CMD_INIT: // Send ACK to host, go to CONNECTED state if successful. sendInitAck(); // Reset timers channel_timer = bootloader_timer = 0; break; // Host starts a firmware update. case CMD_UPDATE_START: if (state == CONNECTED) { // Initiate firmware updates, go to RECEIVING_FIRMWARE state // if successful. startFirmwareUpdate(); } #ifdef DEBUG_LED_ P0 = state; #endif break; // Write message containing one hex record. case CMD_WRITE: if (state == RECEIVING_FIRMWARE) { writeHexRecord( ); } #ifdef DEBUG_LED_ P0 = 0x40; #endif break; // Firmware update has been completed. case CMD_UPDATE_COMPLETE: // Check that every byte is received. if (bytes_received == bytes_total) { // Mark firmware as successfully installed. flash_write_byte(FW_NUMBER, firmware_number); state = CONNECTED; send(CMD_ACK,1); } else { send(CMD_NACK,1); } if (!send_success) { state = ERROR; } #ifdef DEBUG_LED_ P0 = 0x10; #endif break; // Host request data from flash at specified address. case CMD_READ: readHexRecord(); #ifdef DEBUG_LED_ P0 = 0x20; #endif break; // Host sends pong to keep connections with device. case CMD_PONG: send(CMD_PING,1); #ifdef DEBUG_LED_ P0 = 0x80; #endif break; // Host sends disconnect case CMD_EXIT: send(CMD_ACK,1); if(send_success)running=false; state = PINGING; break; // These commands should no be received. case CMD_NO_CMD: default: state = ERROR; break; } // Clear command cmd = CMD_NO_CMD; }else{ //Host app do not reply, reping send(CMD_PING,1); } }else{ //host unreached if (state == PINGING) { // Will ping to one channel for 'a while' before changing. if (++channel_timer > CHANNEL_TIMEOUT) { channel_timer = 0; // Go to next channel ch_i = (ch_i+1)%CHANNEL_SIZE; rf_set_channel(default_channels[ch_i]); #ifdef DEBUG_LED_ P0 = ch_i; #endif // After changing channels and being in the PINGING state // for 'a while', boot loader loop will check if there is firmware // installed, and if so end the while(running) loop. if (++bootloader_timer > BOOTLOADER_TIMEOUT) { bootloader_timer = 0; running = (flash_read_byte(FW_NUMBER) != 0xFF) ? false : true; }else send(CMD_PING,1); } }else { if (++connection_timer > CONNECTION_TIMEOUT) state = PINGING; send(CMD_PING,1); } } } resetRF(); #ifdef DEBUG_LED_ // Default value for P0DIR P0 = 0x00; P0DIR = 0xFF; #endif // Reads address of firmware's reset vector. temp_data[0] = flash_read_byte(FW_RESET_ADDR_H); temp_data[1] = flash_read_byte(FW_RESET_ADDR_L); // sti(); //Should we enable irqs? or should the firmware enable it later? // Jump to firmware. Goodbye! ((firmware_start)(((uint16_t)temp_data[0]<<8) | (temp_data[1])))(); }
// Bootloader protocol logic // static void bootloader(void) { uint8_t c; uint8_t count, i; static uint16_t address; // Wait for a command byte LED_BOOTLOADER = LED_ON; c = cin(); LED_BOOTLOADER = LED_OFF; // common tests for EOC switch (c) { case PROTO_GET_SYNC: case PROTO_GET_DEVICE: case PROTO_CHIP_ERASE: case PROTO_PARAM_ERASE: case PROTO_READ_FLASH: case PROTO_DEBUG: if (cin() != PROTO_EOC) goto cmd_bad; } switch (c) { case PROTO_GET_SYNC: // sync break; case PROTO_GET_DEVICE: cout(BOARD_ID); cout(board_frequency); break; case PROTO_CHIP_ERASE: // erase the program area flash_erase_app(); break; case PROTO_PARAM_ERASE: flash_erase_scratch(); break; case PROTO_LOAD_ADDRESS: // set address address = cin(); address |= (uint16_t)cin() << 8; if (cin() != PROTO_EOC) goto cmd_bad; break; case PROTO_PROG_FLASH: // program byte c = cin(); if (cin() != PROTO_EOC) goto cmd_bad; flash_write_byte(address++, c); break; case PROTO_READ_FLASH: // readback byte c = flash_read_byte(address++); cout(c); break; case PROTO_PROG_MULTI: count = cin(); if (count > sizeof(buf)) goto cmd_bad; for (i = 0; i < count; i++) buf[i] = cin(); if (cin() != PROTO_EOC) goto cmd_bad; for (i = 0; i < count; i++) flash_write_byte(address++, buf[i]); break; case PROTO_READ_MULTI: count = cin(); if (cin() != PROTO_EOC) goto cmd_bad; for (i = 0; i < count; i++) { c = flash_read_byte(address++); cout(c); } break; case PROTO_REBOOT: // generate a software reset, which should boot to the application RSTSRC |= (1 << 4); case PROTO_DEBUG: // XXX reserved for ad-hoc debugging as required break; default: goto cmd_bad; } sync_response(); cmd_bad: return; }