Sophie Dexter
/
Just4Trionic
Just4Trionic - CAN and BDM FLASH programmer for Saab cars
Diff: bdmtrionic.cpp
- Revision:
- 1:d5452e398b76
- Child:
- 2:bf3a2b29259a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bdmtrionic.cpp Tue Sep 14 21:02:04 2010 +0000 @@ -0,0 +1,894 @@ +/******************************************************************************* + +bdmtrionic.cpp +(c) 2010 by Sophie Dexter + +General purpose BDM functions for Just4Trionic by Just4pLeisure + +A derivative work based on: +//----------------------------------------------------------------------------- +// CAN/BDM adapter firmware +// (C) Janis Silins, 2010 +// $id$ +//----------------------------------------------------------------------------- + +******************************************************************************** + +WARNING: Use at your own risk, sadly this software comes with no guarantees. +This software is provided 'free' and in good faith, but the author does not +accept liability for any damage arising from its use. + +*******************************************************************************/ + +#include "bdmtrionic.h" + +// structure for command address/value pairs +struct mempair_t { + uint32_t addr; ///< target address + uint16_t val; ///< word value +}; + +// word write algorithm (29Fxxx) +static const struct mempair_t am29_write [] = { + {0xaaaa, 0xaaaa}, {0x5554, 0x5555}, {0xaaaa, 0xa0a0}, +}; + +// chip erase algorithms +static const struct mempair_t am29_erase [] = { + {0xaaaa, 0xaaaa}, {0x5554, 0x5555}, {0xaaaa, 0x8080}, + {0xaaaa, 0xaaaa}, {0x5554, 0x5555}, {0xaaaa, 0x1010} +}; + +// reset algorithms +//static const struct mempair_t am29_reset = {0xfffe, 0xf0f0}; +static const struct mempair_t am29_reset [] = { + {0xaaaa, 0xaaaa}, {0x5554, 0x5555}, {0xaaaa, 0xf0f0}, +}; + +// chip id algorithms +static const struct mempair_t am29_id [] = { + {0xaaaa, 0xaaaa}, {0x5554, 0x5555}, {0xaaaa, 0x9090}, +}; + +// ;-) +static const struct mempair_t flash_tag [] = { + {0x7fe00, 0xFF4A}, {0x7fe02, 0x7573}, {0x7fe04, 0x7434}, {0x7fe06, 0x704C}, + {0x7fe08, 0x6569}, {0x7fe0a, 0x7375}, {0x7fe0c, 0x7265}, {0x7fe0e, 0x3B29}, +}; + +// local functions +bool reset_am29(void); +bool erase_am29(); +bool flash_am29(const uint32_t* addr, uint16_t value); +bool reset_am28(void); +bool erase_am28(const uint32_t* start_addr, const uint32_t* end_addr); +bool flash_am28(const uint32_t* addr, uint16_t value); +bool get_flash_id(uint8_t* make, uint8_t* type); + + +//----------------------------------------------------------------------------- +/** + Dumps contents of a memory block from [start_addr] up to, but not including, + the [end_addr] as long words (word-aligned addresses). MCU must be in + background mode. The operation interrupts if the break character is + received. + + @param start_addr block start address + @param end_addr block end address + + @return status flag +*/ + + +uint8_t dump_flash(const uint32_t* start_addr, const uint32_t* end_addr) { + + // check parametres + if (*start_addr > *end_addr) { + return TERM_ERR; + } + + // dump memory contents + uint32_t curr_addr = *start_addr; + uint32_t value; + + while ((curr_addr < *end_addr) && (pc.getc() != TERM_BREAK)) { + // read long word + if (curr_addr > *start_addr) { + if (memdump_long(&value) != TERM_OK) { + return TERM_ERR; + } + } else { + if (memread_long(&value, &curr_addr) != TERM_OK) { + return TERM_ERR; + } + } + + // send memory value to host + printf("%08X", value); + + // add the terminating character + if (curr_addr < *end_addr - 4) { + pc.putc(TERM_OK); + // light up the activity LED + // led_on(LED_ACT); + led3 = 1; + } + + curr_addr += 4; + } + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Dumps the contents of a T5 ECU to a BIN file on the mbed 'disk' + from [start_addr] up to, but not including, the [end_addr]. + MCU must be in background mode. + + @param start_addr block start address + @param end_addr block end address + + @return status flag +*/ + +uint8_t dump_trionic() { + + // Configure the MC68332 register values to prepare for flashing + printf("I am trying to discover what type of Trionic ECU I am connected to...\r\n"); + prep_t5_do(); + // Work out what type of FLASH chips we want to make a dump file for + uint8_t make; + uint8_t type; + get_flash_id(&make, &type); + // set up chip-specific functions + bool (*reset_func)(); + uint32_t flash_size; + + switch (type) { + case AMD29F400B: + case AMD29F400T: + printf("I have found AMD29F400 type FLASH chips; I must be connected to a T7 ECU :-)\r\n"); + reset_func = &reset_am29; + flash_size = T7FLASHSIZE; + break; + case AMD29F010: + printf("I have found AMD29F010 type FLASH chips; I must be connected to a repaired T5.5 ECU :-)\r\n"); + reset_func = &reset_am29; + flash_size = T55FLASHSIZE; + break; + case AMD28F010: + case INTEL28F010: + printf("I have found 28F010 type FLASH chips; I must be connected to a T5.5 ECU :-)\r\n"); + reset_func = &reset_am28; + flash_size = T55FLASHSIZE; + break; + case AMD28F512: + case INTEL28F512: + printf("I have found 28F512 type FLASH chips; I must be connected to a T5.2 ECU :-)\r\n"); + reset_func = &reset_am28; + flash_size = T52FLASHSIZE; + break; + default: + // unknown flash type + printf("I could not work out what FLASH chips or TRIONIC ECU I am connected to :-(\r\n"); + return TERM_ERR; + } + + // reset the FLASH chips + if (!reset_func()) return TERM_ERR; + + printf("Creating FLASH dump file...\r\n"); + FILE *fp = fopen("/local/original.bin", "w"); // Open "original.bin" on the local file system for writing + if (!fp) { + perror ("The following error occured"); + return TERM_ERR; + } + +// dump memory contents + uint32_t addr = 0x00; + uint32_t long_value; + +// setup start address to dump from + if (memread_long_cmd(&addr) != TERM_OK) return TERM_ERR; + + timer.reset(); + timer.start(); + + while (addr < flash_size) { + uint16_t byte_count = 0; + while (byte_count < FILE_BUF_LENGTH) { + // get long word + if (memget_long(&long_value) != TERM_OK) return TERM_ERR; + addr += 4; + // send memory value to file_buffer before saving to mbed 'disk' + file_buffer[byte_count] = ((uint8_t)(long_value >> 24)); + file_buffer[byte_count+1] = ((uint8_t)(long_value >> 16)); + file_buffer[byte_count+2] = ((uint8_t)(long_value >> 8)); + file_buffer[byte_count+3] = ((uint8_t)long_value); + byte_count +=4; + } +// make the activity led twinkle + led3 = 1; + fwrite(file_buffer, 1, FILE_BUF_LENGTH, fp); + if (ferror (fp)) { + fclose (fp); + printf ("Error writing to the FLASH BIN file.\r\n"); + return TERM_ERR; + } + } + // should 'clear' the BDM connection here but bdm_clear won't compile from here + // instead do a memread (or anything really) but ignore the result because it's not needed for anything + memread_long(&long_value, &addr); + timer.stop(); + printf("Getting the FLASH dump took %#.1f seconds.\r\n",timer.read()); + fclose(fp); + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Erases the flash memory chip starting from [start_addr] up to, but not + including [end_addr] and optionally verifies the result; MCU must be in + background mode. + + @param flash_type type of flash chip + @param start_addr flash start address + @param end_addr flash end address + + @return status flag +*/ +uint8_t erase_flash(const char* flash_type, const uint32_t* start_addr, + const uint32_t* end_addr) { + // AM29Fxxx chips (retrofitted to Trionic 5.x; original to T7) + if (strncmp(flash_type, "29f010", 6) == 0 || + strncmp(flash_type, "29f400", 6) == 0) { + return erase_am29() ? TERM_OK : TERM_ERR; + } + + // AM28F010 chip (Trionic 5.x original) + if (strncmp(flash_type, "28f010", 6) == 0) { + return erase_am28(start_addr, end_addr) ? TERM_OK : TERM_ERR; + } + + return TERM_ERR; +} + +//----------------------------------------------------------------------------- +/** + Writes a batch of long words to the flash starting from [start_addr]. The + operation interrupts if a break character is received. MCU must be in + background mode. + + @param flash_type type of flash chip + @param start_addr block start address + + @return status flag +*/ +uint8_t write_flash(const char* flash_type, const uint32_t* start_addr) { + // set up chip-specific functions + bool (*reset_func)(void); + bool (*flash_func)(const uint32_t*, uint16_t); + + // AM29Fxxx chips (retrofitted to Trionic 5.x, original to T7) + if (strncmp(flash_type, "29f010", 6) == 0 || + strncmp(flash_type, "29f400", 6) == 0) { + reset_func = &reset_am29; + flash_func = &flash_am29; + } else if (strncmp(flash_type, "28f010", 6) == 0) { + // AM28F010 chip (Trionic 5.x original) + reset_func = &reset_am28; + flash_func = &flash_am28; + } else { + // unknown flash type + return TERM_ERR; + } + + // reset the flash + if (!reset_func()) { + return TERM_ERR; + } + + uint32_t curr_addr = *start_addr; + if (strncmp(flash_type, "29f010", 6) == 0) { + curr_addr = 0; + } + + int rx_char = 0; + char rx_buf[8]; + char* rx_ptr; + uint32_t long_value; + bool ret = true; + + // ready to receive data + pc.putc(TERM_OK); + + while (true) { + // receive long words from USB + printf("receive long words from USB\r\n"); + rx_ptr = rx_buf; + do { + rx_char = pc.getc(); + if (rx_char != EOF) { + // have got all characters for one long word + if (rx_ptr > &rx_buf[7]) { + ret = (rx_char == TERM_OK); + break; + } + + // save the character + *rx_ptr++ = (char)rx_char; + } + } while (rx_char != TERM_OK && rx_char != TERM_BREAK); + // end writing + printf("end writing\r\n"); + if (!ret || rx_char == TERM_BREAK) { + break; + } + + // convert value to long word + printf("convert value to long word\r\n"); + if (!ascii2int(&long_value, rx_buf, 8)) { + ret = false; + break; + } + printf("long value %08x \r\n", long_value); + + // write the first word + printf("write the first word\r\n"); + if (!flash_func(&curr_addr, (uint16_t)(long_value >> 16))) { + ret = false; + break; + } + curr_addr += 2; + // write the second word + printf("write the second word\r\n"); + if (!flash_func(&curr_addr, (uint16_t)long_value)) { + ret = false; + break; + } + curr_addr += 2; + + // light up the activity LED +// led_on(LED_ACT); + led3 = 1; + } + + // reset flash + return (reset_func() && ret) ? TERM_OK : TERM_ERR; +} + +//----------------------------------------------------------------------------- +/** + Writes a BIN file to the flash starting from [start_addr]. + The operation ends when no more bytes can be read from the BIN file. + MCU must be in background mode. + + @param flash_type type of flash chip + @param start_addr block start address + + @return status flag +*/ +uint8_t flash_trionic() { + // Configure the MC68332 register values to prepare for flashing + printf("I am trying to discover what type of Trionic ECU I am connected to...\r\n"); + prep_t5_do(); + // Work out what type of FLASH chips we want to program + uint8_t make; + uint8_t type; + get_flash_id(&make, &type); + // set up chip-specific functions + bool (*reset_func)(); + bool (*flash_func)(const uint32_t*, uint16_t); + uint32_t flash_size; + + switch (type) { + case AMD29F400B: + case AMD29F400T: + printf("I have found AMD29F400 type FLASH chips; I must be connected to a T7 ECU :-)\r\n"); + reset_func = &reset_am29; + flash_func = &flash_am29; + flash_size = T7FLASHSIZE; + break; + case AMD29F010: + printf("I have found AMD29F010 type FLASH chips; I must be connected to a repaired T5.5 ECU :-)\r\n"); + reset_func = &reset_am29; + flash_func = &flash_am29; + flash_size = T55FLASHSIZE; + break; + case AMD28F010: + case INTEL28F010: + printf("I have found 28F010 type FLASH chips; I must be connected to a T5.5 ECU :-)\r\n"); + reset_func = &reset_am28; + flash_func = &flash_am28; + flash_size = T55FLASHSIZE; + break; + case AMD28F512: + case INTEL28F512: + printf("I have found 28F512 type FLASH chips; I must be connected to a T5.2 ECU :-)\r\n"); + reset_func = &reset_am28; + flash_func = &flash_am28; + flash_size = T52FLASHSIZE; + break; + default: + // unknown flash type + printf("I could not work out what FLASH chips or TRIONIC ECU I am connected to :-(\r\n"); + return TERM_ERR; + } + + // reset the FLASH chips + if (!reset_func()) return TERM_ERR; + + printf("Checking the FLASH BIN file...\r\n"); + FILE *fp = fopen("/local/modified.hex", "r"); // Open "modified.hex" on the local file system for reading + if (!fp) { + printf("Error: I could not find the BIN file MODIFIED.HEX\r\n");; + return TERM_ERR; + } + // obtain file size - it should match the size of the FLASH chips: + fseek (fp , 0 , SEEK_END); + uint32_t file_size = ftell (fp); + rewind (fp); + + // read the initial stack pointer value in the BIN file - it should match the value expected for the type of ECU + uint8_t stack_byte = 0; + uint32_t stack_long = 0; + if (!fread(&stack_byte,1,1,fp)) return TERM_ERR; + stack_long |= (stack_byte << 24); + if (!fread(&stack_byte,1,1,fp)) return TERM_ERR; + stack_long |= (stack_byte << 16); + if (!fread(&stack_byte,1,1,fp)) return TERM_ERR; + stack_long |= (stack_byte << 8); + if (!fread(&stack_byte,1,1,fp)) return TERM_ERR; + stack_long |= stack_byte; + rewind (fp); + + if (flash_size == T52FLASHSIZE && (file_size != T52FLASHSIZE || stack_long != T5POINTER)) { + fclose(fp); + printf("The BIN file does not appear to be for a T5.2 ECU :-(\r\n"); + printf("BIN file size: %#10x, FLASH chip size: %#010x, Pointer: %#10x.\r\n", file_size, flash_size, stack_long); + return TERM_ERR; + } + if (flash_size == T55FLASHSIZE && (file_size != T55FLASHSIZE || stack_long != T5POINTER)) { + fclose(fp); + printf("The BIN file does not appear to be for a T5.5 ECU :-(\r\n"); + printf("BIN file size: %#10x, FLASH chip size: %#010x, Pointer: %#10x.\r\n", file_size, flash_size, stack_long); + return TERM_ERR; + } + if (flash_size == T7FLASHSIZE && (file_size != T7FLASHSIZE || stack_long != T7POINTER)) { + fclose(fp); + printf("The BIN file does not appear to be for a T7 ECU :-(\r\n"); + printf("BIN file size: %#10x, FLASH chip size: %#010x, Pointer: %#10x.\r\n", file_size, flash_size, stack_long); + return TERM_ERR; + } + + timer.reset(); + timer.start(); + + uint32_t curr_addr = 0; + + switch (type) { + // AM29Fxxx chips (retrofitted to Trionic 5.x; original to T7) + case AMD29F400B: + case AMD29F400T: + case AMD29F010: + printf("Erasing 29F400/010 type FLASH chips...\r\n"); + if (erase_am29() == TERM_ERR) { + printf("WARNING: An error occured when I tried to erase the FLASH chips :-(\r\n"); + return TERM_ERR; + } + break; + // AM28F010 chip (Trionic 5.x original) + case AMD28F010: + case INTEL28F010: + case AMD28F512: + case INTEL28F512: + printf("Erasing 28F010/512 type FLASH chips...\r\n"); + if (erase_am28(&curr_addr, &flash_size) == TERM_ERR) { + printf("WARNING: An error occured when I tried to erase the FLASH chips :-(\r\n"); + return TERM_ERR; + } + break; + default: + // unknown flash type - shouldn't get here hence "Starange!" + printf("Strange! I couldn't work out how to erase the FLASH chips in the TRIONIC ECU that I am connected to :-(\r\n"); + return TERM_ERR; + } + + timer.stop(); + printf("Erasing took %#.1f seconds.\r\n",timer.read()); + + printf("Programming the FLASH chips...\r\n"); + + timer.reset(); + timer.start(); + + uint16_t word_value = 0; + uint8_t byte_value = 0; +// bool ret = true; + +// ready to receive data + while (curr_addr < flash_size) { + // receive bytes from BIN file + //Get a byte - break if no more bytes to get + if (!fread(&byte_value,1,1,fp)) { + fclose(fp); + printf("Error reading the BIN file MODIFIED.HEX"); + break; + } + word_value = (byte_value << 8); + if (!fread(&byte_value,1,1,fp)) { + fclose(fp); + printf("Error reading the BIN file MODIFIED.HEX"); + break; + } + word_value |= byte_value; + + // write the word if it is not 0xffff + if (word_value != 0xffff) { + if (!flash_func(&curr_addr, word_value)) break; + } + curr_addr += 2; + + // make the activity LED twinkle + led3 = 1; + + } + + timer.stop(); + fclose(fp); + + if (curr_addr == flash_size) { + printf("Programming took %#.1f seconds.\r\n",timer.read()); + reset_func(); + for (uint8_t i = 0; i < 8; ++i) { + memread_word(&word_value, &flash_tag[i].addr); + flash_func(&flash_tag[i].addr, (flash_tag[i].val & word_value)); + } + + } else { + printf("WARNING: Oh dear, I couldn't program the FLASH at address 0x%8x.\r\n", curr_addr); + } + +// reset flash + return (reset_func() && (curr_addr == flash_size)) ? TERM_OK : TERM_ERR; +} + +//----------------------------------------------------------------------------- +/** + Resets an AM29Fxxx flash memory chip. MCU must be in background mode. + + @param none + + @return succ / fail +*/ +bool reset_am29(void) { + // execute the reset command +// uint32_t addr = 0xfffe; +// return (memwrite_word(&addr, 0xf0f0) == TERM_OK); + // execute the algorithm + for (uint8_t i = 0; i < 3; ++i) { + if (memwrite_word(&am29_reset[i].addr, am29_reset[i].val) != TERM_OK) return false; + } + return true; +} + +//----------------------------------------------------------------------------- +/** + Erases an AM29Fxxx flash memory chip and verifies the result; MCU must be + in background mode. + + @return succ / fail +*/ +bool erase_am29() { + // reset flash + if (!reset_am29()) { + return false; + } + + // execute the algorithm + for (uint8_t i = 0; i < 6; ++i) { + if (memwrite_word(&am29_erase[i].addr, am29_erase[i].val) != TERM_OK) { + reset_am29(); + return false; + } + } + + // verify the result + uint32_t addr = 0x0; + uint16_t verify_value; + + uint8_t err_cnt = ERR_COUNT; + while (--err_cnt) { + // typical erase time = 1s + // Allow up to 25.5 seconds erase time + wait_ms(100); + if (memread_word(&verify_value, &addr) == TERM_OK && verify_value == 0xffff) { + // erase completed normally + reset_am29(); + return true; + } + } + + // erase failed + reset_am29(); + return false; +} + +//----------------------------------------------------------------------------- +/** + Writes a word to AM29Fxxx flash memory chip and optionally verifies the + result; MCU must be in background mode. + + @param addr destination address + @param val value + + @return succ / fail +*/ +bool flash_am29(const uint32_t* addr, uint16_t value) { + + // execute the algorithm + for (uint8_t i = 0; i < 3; ++i) { + if (memwrite_word(&am29_write[i].addr, am29_write[i].val) != TERM_OK) { + reset_am29(); + return false; + } + } + // write the value + if (memwrite_word(addr, value) != TERM_OK) { + reset_am29(); + return false; + } + // verify the result + uint8_t err_cnt = ERR_COUNT; + while (--err_cnt) { + // Allow up to approx 2.55 milliseconds program time (255 * ~10us BDM memread time) +// wait_ms(10); + uint16_t verify_value; + if ((memread_word(&verify_value, addr) == TERM_OK) && + (verify_value == value)) { + // flashing successful + return true; + } + } + // writing failed + reset_am29(); + return false; +} + +//----------------------------------------------------------------------------- +/** + Resets a AM28Fxxx flash memory chip. MCU must be in background mode. + + @param start_addr flash start address + + @return succ / fail +*/ +bool reset_am28(void) { + uint32_t start_addr = 0x0; + return (memwrite_word(&start_addr, 0xffff) == TERM_OK && + memwrite_word(&start_addr, 0xffff) == TERM_OK); +} + +//----------------------------------------------------------------------------- +/** + Erases an AM28Fxxx flash memory chip and verifies the result; MCU must be + in background mode. + + @param start_addr flash start address + @param end_addr flash end address + + @return succ / fail +*/ +bool erase_am28(const uint32_t* start_addr, const uint32_t* end_addr) { + + // check the addresses + if (!start_addr || !end_addr) return false; + + // reset flash + if (!reset_am28()) return false; + + // write zeroes over entire flash space + uint32_t addr = *start_addr; + + while (addr < *end_addr) { + if (!flash_am28(&addr, 0x0000)) return false; + addr += 2; +// // feedback to host computer +// pc.putc(TERM_OK); + // make the activity LED twinkle +// led3 = (addr & 0x400); + led3 = 1; + } + + // erase flash + addr = *start_addr; + uint8_t verify_value; + + + uint16_t pulse_cnt = 0; + if (memwrite_byte_cmd(NULL) != TERM_OK) { + reset_am28(); + return false; + } + while ((++pulse_cnt < 1000) && (addr < *end_addr)) { + // issue the erase command + if (memwrite_write_byte(&addr, 0x20) != TERM_OK || + memwrite_write_byte(&addr, 0x20) != TERM_OK) break; + wait_ms(10); + + while (addr < *end_addr) { + // issue the verify command + if (memwrite_read_byte(&addr, 0xa0) != TERM_OK) break; +// wait_us(6); + // check the written value + if (memread_write_byte(&verify_value, &addr) != TERM_OK) break; + if (verify_value != 0xff) break; + // succeeded need to check next address + addr++; + // make the activity LED twinkle + led3 = 1; + } + } + // the erase process ends with a BDM_WRITE + BDM_BYTESIZE command left in the BDM + // it is safe to use it to put one of the FLASH chips into read mode and thereby + // leave the BDM ready for the next command + memwrite_nop_byte(start_addr, 0x00); + + reset_am28(); + // check for success + return (addr == *end_addr) ? true : false; +} + +//----------------------------------------------------------------------------- +/** + Writes a byte to AM28Fxxx flash memory chip and verifies the result + A so called 'mask' method checks the FLASH contents and only tries + to program bytes that need to be programmed. + MCU must be in background mode. + + @param addr destination address + @param val value + + @return succ / fail +*/ +bool flash_am28(const uint32_t* addr, uint16_t value) { + + if (!addr) return false; + + uint8_t pulse_cnt = 0; + uint16_t verify_value = 0; + uint16_t mask_value = 0xffff; + + // put flash into read mode and read address + if (memwrite_word_read_word(&verify_value, addr, 0x0000) != TERM_OK) return false; + // return if FLASH already has the correct value - e.g. not all of the FLASH is used and is 0xff + if (verify_value == value) return true; + + while (++pulse_cnt < 25) { + + // set a mask + if ((uint8_t)verify_value == (uint8_t)value) mask_value &= 0xff00; + if ((uint8_t)(verify_value >> 8) == (uint8_t)(value >> 8)) mask_value &= 0x00ff; + + // write the new value + if (memwrite_word_write_word(addr, (0x4040 & mask_value), value) != TERM_OK) break; + // NOTE the BDM interface is slow enough that there is no need for a 10us delay before verifying +// wait_us(10); + // issue the verification command + // NOTE the BDM interface is slow enough that there is no need for a 6us delay before reading back + if (memwrite_word_read_word(&verify_value, addr, (0xc0c0 & mask_value)) != TERM_OK) break; + // check if flashing was successful; + if (verify_value == value) return true; + } + + // something went wrong; reset the flash chip and return failed + reset_am28(); + return false; +} + +//----------------------------------------------------------------------------- +/** + Does the equivalent of do prept5.do in BD32 + Sets up all of the control registers in the MC68332 so that we can program + the FLASH chips + + @param none + + @return succ / fail +*/ + +uint8_t prep_t5_do(void) { + + // reset and freeze the MC68332 chip + if (restart_chip() != TERM_OK) return TERM_ERR; + + // set the 'fc' registers to allow supervisor mode access + uint32_t long_value = 0x05; + if (sysreg_write(0x0e, &long_value) != TERM_OK) return TERM_ERR; + if (sysreg_write(0x0f, &long_value) != TERM_OK) return TERM_ERR; + + // Set MC68332 to 16 MHz (actually 16.78 MHz) + long_value = 0x00fffa04; + if (memwrite_word(&long_value, 0x7f00) != TERM_OK) return TERM_ERR; + + // Disable watchdog and monitors + long_value = 0x00fffa21; + if (memwrite_byte(&long_value, 0x00) != TERM_OK) return TERM_ERR; + + // Chip select pin assignments + long_value = 0x00fffa44; + if (memwrite_word(&long_value, 0x3fff) != TERM_OK) return TERM_ERR; + + // Boot Chip select read only, one wait state + long_value = 0x00fffa48; + if (memwrite_word(&long_value, 0x0007) != TERM_OK) return TERM_ERR; + if (memfill_word(0x6870) != TERM_OK) return TERM_ERR; + + // Chip select 1 and 2 upper lower bytes, zero wait states + long_value = 0x00fffa50; + if (memwrite_word(&long_value, 0x0007) != TERM_OK) return TERM_ERR; + if (memfill_word(0x3030) != TERM_OK) return TERM_ERR; + if (memfill_word(0x0007) != TERM_OK) return TERM_ERR; + if (memfill_word(0x5030) != TERM_OK) return TERM_ERR; + + // PQS Data - turn on VPPH + long_value = 0x00fffc14; + if (memwrite_word(&long_value, 0x0040) != TERM_OK) return TERM_ERR; + + // PQS Data Direction output + long_value = 0x00fffc17; + if (memwrite_byte(&long_value, 0x40) != TERM_OK) return TERM_ERR; + // wait for programming voltage to be ready + wait_ms(10); + +// // Enable internal 2kByte RAM of 68332 at address 0x00100000 +// long_value = 0x00fffb04; +// if (memwrite_word(&long_value, 0x1000) != TERM_OK) return TERM_ERR; + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Works out what type of flash chip is fitted in the ECU by reading + the manufacturer byte codes. + It is enough to use the 29Fxxx flash id algorithm because 28Fxxx + FLASH chips ignore the first few writes needed by the 29Fxxx chips + MCU must be in background mode. + + @param make (out) + type (out) + + @return succ / fail +*/ +bool get_flash_id(uint8_t* make, uint8_t* type) { + + uint32_t addr = 0x0; + uint32_t value; + bool ret; + // read id bytes algorithm for 29F010/400 FLASH chips + for (uint8_t i = 0; i < 3; ++i) { + if (memwrite_word(&am29_id[i].addr, am29_id[i].val) != TERM_OK) return false; + } + if (memread_long(&value, &addr) != TERM_OK) return false; + *make = (uint8_t)(value >> 24); + *type = (uint8_t)(value >> 8); + printf("FLASH id bytes: %08x, make: %02x, type: %02x\r\n", value, *make, *type); + switch (*type) { + case AMD29F400B: + case AMD29F400T: + case AMD29F010: + case AMD28F010: + case INTEL28F010: + case AMD28F512: + case INTEL28F512: + ret = true; + default: + ret = false; + } + return ret; +} + +//----------------------------------------------------------------------------- +// EOF +//-----------------------------------------------------------------------------