/* NanoStack: MCU software and PC tools for IP-based wireless sensor networking. Copyright (C) 2006-2007 Sensinode Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Address: Sensinode Ltd. Teknologiantie 6 90570 Oulu, Finland E-mail: info@sensinode.com */ #include #ifdef PLATFORM_WINDOWS #include #endif #include "cdi.h" /*read none/8*/ #define CDI_CHIP_ERASE 0x10 #define CDI_WR_CONFIG 0x19 #define CDI_SET_HW_BRKPNT 0x3B /*read 8*/ #define CDI_RD_CONFIG 0x24 #define CDI_READ_STATUS 0x34 #define CDI_HALT 0x44 #define CDI_RESUME 0x4C #define CDI_STEP_INSTR 0x5C /*variable len, add data length to command byte*/ #define CDI_DBGINSTR 0x54 #define CDI_STEP_REPLACE 0x64 /*response = 16 bits*/ #define CDI_GET_PC 0x28 #define CDI_GET_CHIP_ID 0x68 /* internals */ void cdi_command_push(uint8_t *byte, uint8_t bytes_out, uint16_t *retval, uint8_t return_bits); void cdi_flash_bank(uint8_t bank, uint8_t unif_mode); void cdi_dptr_write(uint16_t value); uint8_t cdi_reg_read(uint8_t reg_addr); void cdi_reg_write(uint8_t reg_addr, uint8_t value); void cdi_xdata_write(uint8_t value); uint8_t cdi_xdata_read(void); void cdi_flash_init(void); void cdi_flash_write_page(void); uint32_t cdi_addr = 0; #define pause_ms(x) usleep(x*1000) #define pause_us(x) usleep(x) void cdi_command_push(uint8_t *byte, uint8_t bytes_out, uint16_t *retval, uint8_t return_bits) { uint8_t i, val; for (i=0; i>= 3; for (i=0; i> 8); /*immediateh*/ out[3] = value; /*immediatel*/ cdi_command_push(out, 4, &retval, 8); } uint8_t cdi_reg_read(uint8_t reg_addr) { uint8_t out[3]; uint16_t retval; out[0] = CDI_DBGINSTR + 2; /*command length 2 bytes*/ out[1] = 0xE5; /*mov a, sfr*/ out[2] = reg_addr; /*sfr = reg_addr*/ cdi_command_push(out, 3, &retval, 8); return (uint8_t) retval; } void cdi_flash_bank(uint8_t bank, uint8_t unif_mode) { uint8_t out; out = (bank << 4) + 1; out &= 0x31; if (unif_mode) out |= 0x40; /*set unified memory model*/ cdi_reg_write(0xC7, out); } void cdi_flash_read(uint8_t *ptr, uint16_t bytes) { uint16_t i; uint8_t out[4]; uint16_t retval; cdi_flash_bank((cdi_addr >> 15), 0); cdi_dptr_write(cdi_addr | 0x8000); for (i=0; i> 10) & 0x7F); /*sfr = FADDRH*/ cdi_reg_write(0xAC, (cdi_addr >> 2)); /*sfr = FADDRL*/ /*erase page*/ cdi_reg_write(0xAE, 0x01); pause_ms(40); /*set program counter*/ out[0] = CDI_DBGINSTR + 3; /*command length 3 bytes*/ out[1] = 0x02; /*ljmp immediate16*/ out[2] = 0xE0; /*immediateh*/ out[3] = 0x00; /*immediatel*/ cdi_command_push(out, 4, &retval, 8); /*set breakpoint*/ out[0] = CDI_SET_HW_BRKPNT; /*command length 3 bytes*/ out[1] = 0x04; out[2] = 0xE0; /*immediateh*/ out[3] = sizeof(cdi_ram_code)-2; /*immediatel*/ cdi_command_push(out, 4, &retval, 0); cdi_dptr_write(0xE800); /*data area, set your page data here*/ /*execute*/ out[0] = CDI_RESUME; /*command length 3 bytes*/ cdi_command_push(out, 1, &retval, 8); pause_ms(30); out[3]= 0; do { pause_ms(20); out[0] = CDI_READ_STATUS; cdi_command_push(out, 1, &retval, 8); printf("-"); fflush(stdout); }while( ((retval & 0x20) == 0) && (out[3]++ < 200) ); } int cdi_flash_write(uint8_t *ptr, uint16_t length) { uint16_t i, retval; uint8_t out[3]; if (length > 2048) return -1; cdi_addr &= 0x1F800; /*make sure address is on page boundary*/ printf("0x%6.6X: ", cdi_addr); fflush(stdout); cdi_dptr_write(0xE800); /*our page data buffer is here*/ for (i=0; i< length; i++) { cdi_xdata_write(*ptr++); if ((i & 0x3F) == 0) { printf("."); } if ((i & 0x0F) == 0x00) { printf("\bo"); } if ((i & 0x0F) == 0x08) { printf("\b."); } fflush(stdout); } while(i<2048) { cdi_xdata_write(0xFF); if ((i & 0x3F) == 0) { printf("."); } if ((i & 0x0F) == 0x00) { printf("\bo"); } if ((i & 0x0F) == 0x08) { printf("\b."); } fflush(stdout); i++; } out[0] = CDI_HALT; cdi_command_push(out, 1, &retval, 8); out[0] = CDI_READ_STATUS; retval = 0; cdi_command_push(out, 1, &retval, 8); if ((retval & 0xFF) == 0xB2) { /*restore config*/ out[0] = CDI_WR_CONFIG; /*command length 3 bytes*/ out[1] = 0x0E; /*write flash area*/ cdi_command_push(out, 2, &retval, 0); /*set flash timings and copy code to ram*/ cdi_flash_init(); /*write page*/ cdi_flash_write_page(); cdi_addr += 2048; /*increment page address*/ pause_ms(10); } else { return -1; } return 0; } int cdi_flash_write_mac(uint8_t *ptr) { uint16_t i, retval; uint8_t out[3]; cdi_addr = 0x1F800; /*last page*/ printf("0x%6.6X", cdi_addr); fflush(stdout); cdi_dptr_write(0xEFF8); /*our page data buffer is here*/ for (i=0; i<8; i++) { cdi_xdata_write(*ptr++); if ((i & 0x0F) == 0) { printf("."); fflush(stdout); } } out[0] = CDI_HALT; cdi_command_push(out, 1, &retval, 8); out[0] = CDI_READ_STATUS; retval = 0; cdi_command_push(out, 1, &retval, 8); if ((retval & 0xFF) == 0xB2) { /*restore config*/ out[0] = CDI_WR_CONFIG; /*command length 3 bytes*/ out[1] = 0x0E; /*write flash area*/ cdi_command_push(out, 2, &retval, 0); /*set flash timings and copy code to ram*/ cdi_flash_init(); /*write page*/ cdi_flash_write_page(); cdi_addr += 2048; /*increment page address*/ pause_ms(10); } else { return -1; } return 0; } int cdi_start(uint16_t *chip_id) { uint8_t out[3]; uint16_t retval; prog_start(); /*do the CDI startup sequence*/ out[0] = CDI_READ_STATUS; cdi_command_push(out, 1, &retval, 8); printf("Status: %2.2X.\n", retval & 0xFF); out[0] = CDI_GET_CHIP_ID; cdi_command_push(out, 1, &retval, 16); *chip_id = retval; out[0] = CDI_HALT; cdi_command_push(out, 1, &retval, 8); pause_ms(100); out[0] = CDI_WR_CONFIG; /*command length 3 bytes*/ out[1] = 0x0E; /*write flash area*/ cdi_command_push(out, 2, &retval, 0); pause_ms(10); cdi_reg_write(0xC6, 0xC9); /*sfr = CLKCON*/ pause_ms(10); cdi_reg_write(0xAB, 0x15); /*sfr = FWT*/ cdi_addr = 0; return 0; } int cdi_erase(void) { uint8_t out[3]; uint16_t retval; uint8_t i; out[0] = CDI_WR_CONFIG; out[1] = 0x0E; cdi_command_push(out, 2, &retval, 0); out[0] = CDI_CHIP_ERASE; cdi_command_push(out, 1, &retval, 0); retval = 0; i = 0; do { pause_ms(30); out[0] = CDI_READ_STATUS; cdi_command_push(out, 1, &retval, 8); }while( ((retval & 0x84) != 0x80) && (i++ < 100) ); cdi_addr = 0; if (i >= 100) { return -1; } return 0; } void cdi_set_address(uint32_t address) { cdi_addr = address; }