📄 bootloader.c
字号:
/*============================================================================Cyan Technology LimitedFILE - bootloader.cDESCRIPTION Accepts an entire eCOG ROM file on UART A in binary and copies it to flash memory. This program is intended to run from RAM. The code then executes when the eCOG is restarted with GPIO4 low (DIP SW1 closed). Version 2.0 supports binary format only, and tramsission is via UART A and the XModem-1k protocol with CRC checking. CHANGE LOG 27/11/04 - Version 1.0 - Tony Ward 20/06/05 - Version 2.0 - Tony Ward Updated receive function to transmit start character ('C'), previously transmitted using init function 08/05/05 - V2.1 ADC Updated code sytle 08/25/05 - V2.2 TW Fixed errors at start of file download Added support for partial image files 02/11/05 - V2.3 EJH Added retransmission of initial C to start download Added new CRC16 calculation code to remove the need for the 256 word lookup table.=============================================================================*/// Defines the location of the following code in memory - see cstartup.asm#pragma code_segment BOOTLOADER#include <ecog.h>#include <ecog1.h>#include "driver_lib.h"#define PROGRAM_FLASH 1#define ENABLE_TIMEOUT 1#define FALSE 0#define TRUE !FALSE#define NULL ((void *)0)typedef unsigned int bool;// XModem timeouts#define TIMEOUT 5120 // 5 second timeout#define MAX_RETRY 5// ASCII control codes#define SOH 1#define STX 2#define ETX 3#define EOT 4#define ACK 6#define NAK 21#define CAN 24 // cancel#define CRC 'C' // use format with CRC// Error valuestypedef enum{ E_NONE = 0, E_ABORT, // 1 E_RETRY, // 2 E_TIMEOUT, // 3 E_OVF, // 4 E_EOT, // 5 E_PKT1, // 6 E_PKT2, // 7 E_CRC // 8} Error_State_e;// Status valuestypedef enum{ S_OK = 1, // 1 - General OK status for higher level S_PKT128, // 2 - 128 byte packet received S_PKT1024, // 3 - 1024 byte packet received S_RETRY, // 4 - Retry S_EOT, // 5 - End of transmission (EOT) S_PKTERR, // 6 - Packet number error S_CRCERR, // 7 - CRC error S_MAXRETRY // 8 - Maximum retries exceeded (fatal)} XModem_State_e;/******************************************************************************Declaration of static functions.******************************************************************************/void msec_delay(unsigned int delay);void usec_delay(unsigned int delay);int readchar(void);/******************************************************************************Declaration of public functions.******************************************************************************/int txchar(int c);// The following are used for XModem transferXModem_State_e get_word (unsigned int *ptr);unsigned int get_eot(void);void XM_init(unsigned int max_retries);XModem_State_e XM_rxp(unsigned int *pbuf);// CRC32 calculation routinesunsigned long CalcCrc(unsigned short *ptr, unsigned long count);unsigned long CalcPoly(unsigned long arg);// CRC16 calculation routinesunsigned int Update_crc(unsigned int CrntCRC, unsigned char Data);// Flash memory routinesvoid flash_erase(int first_page, int last_page);void flash_program(unsigned int program_address, unsigned int *ptr, unsigned int count);static int retry_max; /******************************************************************************NAME bootloaderSYNOPSIS void bootloader(void)FUNCTION Main code function. Responsible for receiving the ROM file, performing validation and writing it to the flash memoryRETURNS after programming of flash memory is complete******************************************************************************/void bootloader(void){ // Application specific parameters unsigned int app_size = 0; // Size of application (KB) unsigned long app_crc = 0; // CRC of entire application (CRC32) // Binary file parameters for reading and programming unsigned int *buffer = (unsigned int *)0x8c00; // Page buffer in cache unsigned int *ptr = buffer; // Pointer to buffer XModem_State_e status = S_OK; // Return status from get_word int page; // Page (programming address) int data_size = 256; // Flash buffer size int program_address = 0; unsigned int alpha; // Temporary variable int i; // Loop counter // Map cache bank 1 as ram for flash programming buffer area rg.mmu.cache1_data_log = (unsigned int)buffer >> 8; fd.mmu.translate_en.cache1_data = 1; fd.tim.int_dis1.cnt1_exp = 1; // Disable the timer expiry interrupt XM_init(MAX_RETRY); // Initialise XModem crc table // Erase any user program in flash memory (pages from 0x0100 to 0x6f00) flash_erase(1, 0x6f); // Prepare flash data using a 1k buffer, page by page for (page = 0x0; (page < 0x71) && (S_OK == status); page++) { ptr = buffer; for (i = 0; i <= 255; i++) // Clear buffer { *ptr++ = 0xffff; } ptr = buffer; if (0 == page) // First page, read interrupt vectors and change them to branch instructions { for (i = 0; (i < 4) && (S_OK == status); i++) // Copy first four words (reset branch) { status = get_word(ptr++); } for (; (i <= 0x38) && (S_OK == status); i++) // Interrupt vectors { /* Each vector address is converted into a two word branch instruction * with a relative address, programmed in the 2nd page of flash (0x0100 to 0x01ff). * The interrupt vectors are static and defined in irq.asm. */ status = get_word(&alpha); if (S_OK == status) { alpha = alpha - (i << 1) - 0x101 + 4; if (alpha & 0x0080) { alpha += 0x100; } *ptr++ = (alpha & 0xff00); *ptr++ = ((alpha & 0x00ff) << 8) | 0x00e0; } } // Discard the rest of the downloaded first page (should be blank) for (; (i <= 255) && (S_OK == status); i++) { status = get_word(&alpha); } data_size = (S_OK != status) ? 0 : i; program_address = 0x100; } /* It is possible that the image file does not contain an entire flash memory * dump. If this occurs outside of the following loop then this is an error */ else if ((page > 0) && (page < 0x70) && (S_OK == status)) // Data page, read and program { // Get the data for (i = 0; (i <= 255) && (S_OK == status); i++) { status = get_word(ptr++); } // Set the parameters data_size = ((1 == page) || (S_OK != status)) ? 0 : i; // Skip programming page 1 program_address = page << 8; app_size += data_size; } else if (0x70 == page) // End of flash memory, discard rest of file { while (status != S_EOT) { status = get_word(&alpha); // Keep checking for the EOT packet } } if (S_EOT == status) { // End of file, program size and checksum // Map flash to data space and calculate the crc rg.mmu.flash_data_log = 0x0000; // Logical data address rg.mmu.flash_data_phy = 0x0000; // Physical flash address rg.mmu.flash_data_size = 0x7f; // 32k words of flash rg.mmu.translate_en |= 0x0010; // Enable flash data translation // Calculate checksum over downloaded application file app_crc = CalcCrc((unsigned short *)0x0200, app_size); rg.mmu.translate_en &= ~0x0010; // Disable flash data translation // Store application size and checksum to flash ptr = buffer; *ptr++ = app_size; *ptr++ = (unsigned int)(app_crc >> 16); //MSW *ptr++ = (unsigned int)(app_crc & 0xffff); //LSW data_size = 3; program_address = 0x01fd; // Save these at end of page 1 // NB These are not included in checksum calculation } // Program the buffer to the flash memory flash_program(program_address, buffer, data_size); } // Tidy up and exit txchar('D'); txchar('o'); txchar('n'); txchar('e'); brk(); return; // Stop for now, work out what to do later} /******************************************************************************NAME get_wordSYNOPSIS int get_word(void)FUNCTION Gets a single word from the XModem buffer, refills buffer if necessary Initialisation is also automaticRETURNS The next byte in the buffer and S_OK******************************************************************************/XModem_State_e get_word(unsigned int *ptr){ static XModem_State_e status = S_OK; static unsigned int index = 0; static unsigned int size = 0; // NB word address 0x8800 is equivalent to byte address 0x11000 static unsigned int *bufptr = (unsigned int *)0x8800; // Cache buffer if (index >= size) index = 0; if (index == 0) // Read new packet into buffer memory { status = XM_rxp(bufptr); // Get packet size in words if (status == S_PKT1024) { size = 512; status = S_OK; } else if (status == S_PKT128) { size = 64; status = S_OK; } } if ((S_OK == status) && (ptr != NULL)) { *ptr = (bufptr[index++]); } return (status);}/******************************************************************************NAME XM_initSYNOPSIS void XM_init(unsigned int max_retries)FUNCTION Performs all the initalisation for the XModem transfer.RETURNS Nothing******************************************************************************/void XM_init(unsigned int max_retries){ unsigned int timeout = TIMEOUT; retry_max = max_retries; // Set global variable rg.cache.ctrl = 0; // Enable cache data access rg.mmu.cache0_data_log = 0x0088; // Map in the cache as data buffer rg.mmu.translate_en = rg.mmu.translate_en | 0x0180; // Timer initialisation fd.ssm.rst_clr.low_ref_div_chn = 1; // Bring Low reference clock up fd.ssm.div_sel.low_clk_timer = 1; // Use the low freq clock fd.ssm.div_sel.cnt1 = 0; // Use the reference fd.ssm.tap_sel2.cnt1 = 3; // Divide by 32 = 1 m second intervals fd.ssm.clk_en.cnt1 = 1; // Enable the timer fd.ssm.rst_clr.cnt1 = 1; // Take the timer out of reset rg.tim.cnt1_ld = timeout; // Set the timer load value fd.tim.ctrl_en.cnt1_cnt = 1; // Start counting}/******************************************************************************NAME XM_rxpSYNOPSIS XModem_State_e XM_rxp(unsigned int *pbuf)FUNCTION Receives the next XModem packet from the serial port. Handles all the CRC checking and retying.RETURNS S_PKT128 128 byte packet received S_PKT1024 1024 byte packet received S_RETRY requested resend S_EOT end of transmission (EOT) S_CRCERR CRC error S_MAXRETRY maximum retries exceeded (fatal) ******************************************************************************/XModem_State_e XM_rxp(unsigned int *pbuf){ static bool ack_flag = FALSE; static int packet_num = 0; static bool start_flag = TRUE; int retries = 0; int c; // Input character unsigned int i; // Loop counter XModem_State_e result; // Return value unsigned int packet_len = 0; unsigned int crc = 0; Error_State_e error; unsigned char *ptr = (unsigned char *)pbuf; int done = FALSE; // Read one XModem packet into buffer, retry if any errors do { error = E_NONE; // Reset these for each retry do { if (start_flag) // Start of transmission ? { txchar(CRC); // ..yes, send C to start CRC transfer } else if (ack_flag) // Acknowledge last packet ? { txchar(ACK); // ..yes, send ACK to request next packet ack_flag = FALSE; // Reset flag } // Look for the start of the next packet c = readchar(); if (c < 0) { result = S_RETRY; error = E_TIMEOUT; break; } if (++packet_num > 255) // Increment packet number, restart at 0 if > 255 { packet_num = 0; } switch (c) { case SOH: start_flag = FALSE; // Clear the start condition packet_len = 128; // 128 byte packet result = S_PKT128; break; case STX: start_flag = FALSE; // Clear the start condition packet_len = 1024; // 1024 byte packet result = S_PKT1024; break; case CAN: // Cancel received case EOT: // EOT received - stop txchar(ACK); // Send ACK result = S_EOT; error = E_EOT; done = TRUE; break; default: // Unexpected character, could be mid packet, check for duart overflow while (fd.duart.a_sts.rx_ofl) { // We have an overflow, wait for end of packet unsigned int save = rg.tim.cnt1_ld; // back up timer load value rg.tim.cnt1_ld = 10; // set for 10 ms delays fd.tim.cmd.cnt1_ld = 1; // Load the timer while (rg.tim.cnt1_cnt) { if (fd.duart.a_sts.rx_1b_rdy) { fd.tim.cmd.cnt1_ld = 1; // Reset timer c = rg.duart.a_rx; // Empty buffer } } fd.duart.a_int_clr.rx_ofl = 1; // Clear overflow
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -