Sophie Dexter
/
Just4Trionic
Just4Trionic - CAN and BDM FLASH programmer for Saab cars
Diff: bdmtrionic.cpp
- Revision:
- 4:682d96ff6d79
- Parent:
- 2:bf3a2b29259a
- Child:
- 5:1775b4b13232
--- a/bdmtrionic.cpp Tue Jun 07 12:23:28 2011 +0000 +++ b/bdmtrionic.cpp Wed Sep 11 11:55:51 2013 +0000 @@ -80,7 +80,8 @@ */ -uint8_t dump_flash(const uint32_t* start_addr, const uint32_t* end_addr) { +uint8_t dump_flash(const uint32_t* start_addr, const uint32_t* end_addr) +{ // check parametres if (*start_addr > *end_addr) { @@ -105,6 +106,7 @@ // send memory value to host printf("%08X", value); + printf("\r\n"); // add the terminating character if (curr_addr < *end_addr - 4) { @@ -131,7 +133,8 @@ @return status flag */ -uint8_t dump_trionic() { +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"); @@ -145,6 +148,11 @@ uint32_t flash_size; switch (type) { + case AMD29BL802C: + printf("I have found AMD29BL802C type FLASH chips; I must be connected to a T8 ECU :-)\r\n"); + reset_func = &reset_am29; + flash_size = T8FLASHSIZE; + break; case AMD29F400B: case AMD29F400T: printf("I have found AMD29F400 type FLASH chips; I must be connected to a T7 ECU :-)\r\n"); @@ -193,7 +201,7 @@ timer.reset(); timer.start(); - + printf(" 0.00 %% complete.\r"); while (addr < flash_size) { uint16_t byte_count = 0; while (byte_count < FILE_BUF_LENGTH) { @@ -207,7 +215,7 @@ file_buffer[byte_count+3] = ((uint8_t)long_value); byte_count +=4; // make the activity led twinkle - ACTIVITYLEDON; + ACTIVITYLEDON; } fwrite(file_buffer, 1, FILE_BUF_LENGTH, fp); if (ferror (fp)) { @@ -215,7 +223,9 @@ printf ("Error writing to the FLASH BIN file.\r\n"); return TERM_ERR; } + printf("%6.2f\r", 100*(float)addr/(float)flash_size ); } + printf("\n"); // 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); @@ -238,7 +248,8 @@ @return status flag */ uint8_t erase_flash(const char* flash_type, const uint32_t* start_addr, - const uint32_t* end_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) { @@ -264,7 +275,8 @@ @return status flag */ -uint8_t write_flash(const char* flash_type, const uint32_t* start_addr) { +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); @@ -349,7 +361,7 @@ curr_addr += 2; // light up the activity LED - ACTIVITYLEDON; + ACTIVITYLEDON; } // reset flash @@ -367,7 +379,8 @@ @return status flag */ -uint8_t flash_trionic() { +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(); @@ -381,6 +394,12 @@ uint32_t flash_size; switch (type) { + case AMD29BL802C: + printf("I have found AMD29BL802C type FLASH chips; I must be connected to a T8 ECU :-)\r\n"); + reset_func = &reset_am29; + flash_func = &flash_am29; + flash_size = T8FLASHSIZE; + break; case AMD29F400B: case AMD29F400T: printf("I have found AMD29F400 type FLASH chips; I must be connected to a T7 ECU :-)\r\n"); @@ -415,6 +434,7 @@ } // reset the FLASH chips + printf("Reset the FLASH chip(s) to prepare them for Erasing\r\n"); if (!reset_func()) return TERM_ERR; printf("Checking the FLASH BIN file...\r\n"); @@ -459,6 +479,12 @@ 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 == T8FLASHSIZE && (file_size != T8FLASHSIZE || stack_long != T8POINTER)) { + fclose(fp); + printf("The BIN file does not appear to be for a T8 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(); @@ -467,10 +493,11 @@ switch (type) { // AM29Fxxx chips (retrofitted to Trionic 5.x; original to T7) + case AMD29BL802C: case AMD29F400B: case AMD29F400T: case AMD29F010: - printf("Erasing 29F400/010 type FLASH chips...\r\n"); + printf("Erasing 29BL802/F400/010 type FLASH chips...\r\n"); if (!erase_am29()) { printf("WARNING: An error occured when I tried to erase the FLASH chips :-(\r\n"); return TERM_ERR; @@ -488,7 +515,7 @@ } break; default: - // unknown flash type - shouldn't get here hence "Starange!" + // unknown flash type - shouldn't get here hence "Strange!" 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; } @@ -506,6 +533,7 @@ // bool ret = true; // ready to receive data + printf(" 0.00 %% complete.\r"); while (curr_addr < flash_size) { // receive bytes from BIN file //Get a byte - break if no more bytes to get @@ -529,40 +557,46 @@ curr_addr += 2; // make the activity LED twinkle - ACTIVITYLEDON; + ACTIVITYLEDON; + if (!(curr_addr % 0x80)) + printf("%6.2f\r", 100*(float)curr_addr/(float)flash_size ); } - + printf("\n"); 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 { + // "Just4pleisure;)" 'tag' in the empty space at the end of the FLASH chip + // Removed for now because it conflicts with some information that Dilemma places in this empty space + // and because it is unsafe for Trionic 8 ECUs which have much bigger BIN files and FLASH chips + // 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 + // 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. +Resets an AM29Fxxx flash memory chip. MCU must be in background mode. - @param none +@param none - @return succ / fail +@return succ / fail */ -bool reset_am29(void) { +bool reset_am29(void) +{ // execute the reset command -// uint32_t addr = 0xfffe; -// return (memwrite_word(&addr, 0xf0f0) == TERM_OK); + // 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; @@ -572,17 +606,20 @@ //----------------------------------------------------------------------------- /** - Erases an AM29Fxxx flash memory chip and verifies the result; MCU must be - in background mode. +Erases an AM29Fxxx flash memory chip and verifies the result; MCU must be +in background mode. - @return succ / fail +@return succ / fail */ -bool erase_am29() { +bool erase_am29() +{ // reset flash if (!reset_am29()) { return false; } - + printf("Erasing AMD 29Fxxx FLASH chips.\r\n"); + printf("This can take up to a minute for a T8,\r\n"); + printf("30s for a T7 or 15s for a T5 ECU.\r\n"); // execute the algorithm for (uint8_t i = 0; i < 6; ++i) { if (memwrite_word(&am29_erase[i].addr, am29_erase[i].val) != TERM_OK) { @@ -595,17 +632,24 @@ uint32_t addr = 0x0; uint16_t verify_value; + printf(" 0.0 seconds.\r"); uint8_t err_cnt = ERR_COUNT; while (--err_cnt) { // typical erase time = 1s // Allow up to 25.5 seconds erase time wait_ms(100); + wait_ms(100); if (memread_word(&verify_value, &addr) == TERM_OK && verify_value == 0xffff) { // erase completed normally reset_am29(); + printf("\n"); return true; } + // make the activity LED twinkle + ACTIVITYLEDON; + printf("%4.1f\r", (float)ERR_COUNT/5 - (float)err_cnt/5 ); } + printf("\n"); // erase failed reset_am29(); @@ -614,15 +658,16 @@ //----------------------------------------------------------------------------- /** - Writes a word to AM29Fxxx flash memory chip and optionally verifies the - result; MCU must be in background mode. +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 +@param addr destination address +@param val value - @return succ / fail +@return succ / fail */ -bool flash_am29(const uint32_t* addr, uint16_t value) { +bool flash_am29(const uint32_t* addr, uint16_t value) +{ // execute the algorithm for (uint8_t i = 0; i < 3; ++i) { @@ -640,7 +685,8 @@ 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); + // wait_ms(10); + wait_us(100); uint16_t verify_value; if ((memread_word(&verify_value, addr) == TERM_OK) && (verify_value == value)) { @@ -655,28 +701,30 @@ //----------------------------------------------------------------------------- /** - Resets a AM28Fxxx flash memory chip. MCU must be in background mode. +Resets a AM28Fxxx flash memory chip. MCU must be in background mode. - @param start_addr flash start address +@param start_addr flash start address - @return succ / fail +@return succ / fail */ -bool reset_am28(void) { +bool reset_am28(void) +{ uint32_t start_addr = 0x0; return (memwrite_word_write_word(&start_addr, 0xffff, 0xffff) == TERM_OK); } //----------------------------------------------------------------------------- /** - Erases an AM28Fxxx flash memory chip and verifies the result; MCU must be - in background mode. +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 +@param start_addr flash start address +@param end_addr flash end address - @return succ / fail +@return succ / fail */ -bool erase_am28(const uint32_t* start_addr, const uint32_t* end_addr) { +bool erase_am28(const uint32_t* start_addr, const uint32_t* end_addr) +{ // check the addresses if (!start_addr || !end_addr) return false; @@ -687,20 +735,26 @@ // write zeroes over entire flash space uint32_t addr = *start_addr; + printf("First write 0x00 to all FLASH addresses.\r\n"); + printf(" 0.00 %% complete.\r"); while (addr < *end_addr) { if (!flash_am28(&addr, 0x0000)) return false; addr += 2; -// // feedback to host computer -// pc.putc(TERM_OK); + // // feedback to host computer + // pc.putc(TERM_OK); // make the activity LED twinkle - ACTIVITYLEDON; - + ACTIVITYLEDON; + if (!(addr % 0x80)) + printf("%6.2f\r", 100*(float)addr/(float)*end_addr ); } + printf("\n"); // erase flash addr = *start_addr; uint8_t verify_value; + printf("Now erasing FLASH and verfiying that all addresses are 0xFF.\r\n"); + printf(" 0.00 %% complete.\r"); uint16_t pulse_cnt = 0; if (memwrite_byte_cmd(NULL) != TERM_OK) { reset_am28(); @@ -715,16 +769,19 @@ while (addr < *end_addr) { // issue the verify command if (memwrite_read_byte(&addr, 0xa0) != TERM_OK) break; -// wait_us(6); + // 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 - ACTIVITYLEDON; + ACTIVITYLEDON; + if (!(addr % 0x80)) + printf("%6.2f\r", 100*(float)addr/(float)*end_addr ); } } + printf("\n"); // 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 @@ -737,17 +794,18 @@ //----------------------------------------------------------------------------- /** - 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. +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 +@param addr destination address +@param val value - @return succ / fail +@return succ / fail */ -bool flash_am28(const uint32_t* addr, uint16_t value) { +bool flash_am28(const uint32_t* addr, uint16_t value) +{ if (!addr) return false; @@ -785,16 +843,18 @@ //----------------------------------------------------------------------------- /** - 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 +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 +@param none - @return succ / fail +@return succ / fail */ -uint8_t prep_t5_do(void) { +//uint8_t prep_t5_do(void) { +uint8_t prep_t8_do(void) +{ // reset and freeze the MC68332 chip if (restart_chip() != TERM_OK) return TERM_ERR; @@ -804,48 +864,138 @@ 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) + // Set MC68332 to 16 MHz (actually 16.78 MHz) (SYNCR) long_value = 0x00fffa04; if (memwrite_word(&long_value, 0x7f00) != TERM_OK) return TERM_ERR; - // Disable watchdog and monitors + // Disable watchdog and monitors (SYPCR) long_value = 0x00fffa21; if (memwrite_byte(&long_value, 0x00) != TERM_OK) return TERM_ERR; - // Chip select pin assignments + + // Chip select pin assignments (CSPAR0) long_value = 0x00fffa44; if (memwrite_word(&long_value, 0x3fff) != TERM_OK) return TERM_ERR; - // Boot Chip select read only, one wait state + // Boot Chip select read only, one wait state (CSBARBT) 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 + // Chip select 1 and 2 upper lower bytes, zero wait states (CSBAR1, CSOR1, CSBAR2, CSBAR2) 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 + // PQS Data - turn on VPPH (PORTQS) long_value = 0x00fffc14; if (memwrite_word(&long_value, 0x0040) != TERM_OK) return TERM_ERR; - // PQS Data Direction output + // PQS Data Direction output (DDRQS) 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; + // // Enable internal 2kByte RAM of 68332 at address 0x00100000 (TRAMBAR) + // long_value = 0x00fffb04; + // if (memwrite_word(&long_value, 0x1000) != TERM_OK) return TERM_ERR; return TERM_OK; } //----------------------------------------------------------------------------- /** +Does the equivalent of do prept5/7/8.do in BD32 +Sets up all of the control registers in the MC68332/377 so that we can +program the FLASH chips + +@param none + +@return succ / fail +*/ + +uint8_t prep_t5_do(void) +{ + + // reset and freeze the MC68332/377 chip + if (restart_chip() != TERM_OK) return TERM_ERR; + + // define some variables to store address and data values + uint32_t long_value = 0x05; + uint16_t verify_value; + + // set the 'fc' registers to allow supervisor mode access + if (sysreg_write(0x0e, &long_value) != TERM_OK) return TERM_ERR; + if (sysreg_write(0x0f, &long_value) != TERM_OK) return TERM_ERR; + + // Read MC68332/377 Module Control Register (SIMCR/MCR) + // and use the value to work out if ECU is a T5/7 or a T8 + long_value = 0x00fffa00; + if (memread_word(&verify_value, &long_value) != TERM_OK) return TERM_ERR; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// verify_value = 0x7E4F; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // MC68377 MCR = x111111x01001111 binary after a reset + if ((verify_value & 0x7E4F) == 0x7E4F) { + printf ("I have found a Trionic 8 ECU.\r\n"); +// Set MC68377 to double it's default speed (16 MHz?) (SYNCR) + long_value = 0x00fffa08; + // First set the MFD part (change 4x to 8x) + if (memwrite_word(&long_value, 0x6908) != TERM_OK) return TERM_ERR; + // wait for everything to settle (should really check the PLL lock register) + wait_ms(100); + // Now set the RFD part (change /2 to /1) + if (memwrite_word(&long_value, 0x6808) != TERM_OK) return TERM_ERR; + // Disable watchdog and monitors (SYPCR) + long_value = 0x00fffa50; + if (memwrite_word(&long_value, 0x0000) != TERM_OK) return TERM_ERR; + return TERM_OK; + } +// MC68332 SIMCR = 0000x00011001111 binary after a reset + //if ((verify_value & 0x00CF) == 0x00CF) { + else { + printf ("I have found a Trionic 5 or 7 ECU.\r\n"); + // Set MC68332 to 16 MHz (actually 16.78 MHz) (SYNCR) + long_value = 0x00fffa04; + if (memwrite_word(&long_value, 0x7f00) != TERM_OK) return TERM_ERR; + // Disable watchdog and monitors (SYPCR) + long_value = 0x00fffa21; + if (memwrite_byte(&long_value, 0x00) != TERM_OK) return TERM_ERR; + // Chip select pin assignments (CSPAR0) + long_value = 0x00fffa44; + if (memwrite_word(&long_value, 0x3fff) != TERM_OK) return TERM_ERR; + // Boot Chip select read only, one wait state (CSBARBT) + 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 (CSBAR1, CSOR1, CSBAR2, CSBAR2) + 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 (PORTQS) + long_value = 0x00fffc14; + if (memwrite_word(&long_value, 0x0040) != TERM_OK) return TERM_ERR; + // PQS Data Direction output (DDRQS) + 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 (TRAMBAR) + //long_value = 0x00fffb04; + //if (memwrite_word(&long_value, 0x1000) != TERM_OK) return TERM_ERR; + return TERM_OK; + } +// Unknown MC683xx chip if code reaches this point + return TERM_ERR; +} + + +//----------------------------------------------------------------------------- +/** 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 @@ -857,22 +1007,31 @@ @return succ / fail */ -bool get_flash_id(uint8_t* make, uint8_t* type) { +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; + //printf("Getting FLASH chip ID.\r\n"); + if (memwrite_word(&am29_id[i].addr, am29_id[i].val) != TERM_OK) { + printf("There was an error when I tried to request the FLASH chip ID.\r\n"); + return false; + } } - if (memread_long(&value, &addr) != TERM_OK) return false; + if (memread_long(&value, &addr) != TERM_OK) { + printf("Error Reading FLASH chip types in get_flash_id\r\n"); + return false; + } // *make = (uint8_t)(value >> 24); // *type = (uint8_t)(value >> 8); *make = (uint8_t)(value >> 16); *type = (uint8_t)(value); printf("FLASH id bytes: %08x, make: %02x, type: %02x\r\n", value, *make, *type); switch (*type) { + case AMD29BL802C: case AMD29F400B: case AMD29F400T: case AMD29F010: