From bd1e4102286462b13943e9c40e580cd63d821fbe Mon Sep 17 00:00:00 2001 From: Robert Pelnar Date: Fri, 8 Jun 2018 00:20:28 +0200 Subject: [PATCH] New ML support - W25X20CL external spi flash support --- Firmware/Marlin_main.cpp | 72 ++++++++++++++- Firmware/config.h | 3 + Firmware/language.c | 160 ++++++++++++++++++++-------------- Firmware/language.h | 42 ++++++--- Firmware/pins_Einsy_1_0.h | 1 + Firmware/spi.h | 14 ++- Firmware/ultralcd.cpp | 71 ++++++++------- Firmware/ultralcd.h | 2 +- Firmware/w25x20cl.c | 178 ++++++++++++++++++++++++++++++++++++++ Firmware/w25x20cl.h | 40 +++++++++ 10 files changed, 469 insertions(+), 114 deletions(-) create mode 100644 Firmware/w25x20cl.c create mode 100644 Firmware/w25x20cl.h diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 0f74264e..b06e7bfd 100644 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -83,6 +83,9 @@ #include "tmc2130.h" #endif //TMC2130 +#ifdef W25X20CL +#include "w25x20cl.h" +#endif //W25X20CL #ifdef BLINKM #include "BlinkM.h" @@ -982,6 +985,8 @@ void __test() while(1); } +#ifdef W25X20CL + void upgrade_sec_lang_from_external_flash() { if ((boot_app_magic == 0x55aa55aa) && (boot_app_flags & BOOT_APP_FLG_USER0)) @@ -999,11 +1004,54 @@ void upgrade_sec_lang_from_external_flash() boot_app_flags &= ~BOOT_APP_FLG_USER0; } +uint8_t lang_xflash_enum_codes(uint16_t* codes) +{ + lang_table_header_t header; + uint8_t count = 0; + uint32_t addr = 0x00000; + while (1) + { + printf_P(_n("LANGTABLE%d:"), count); + w25x20cl_rd_data(addr, (uint8_t*)&header, sizeof(lang_table_header_t)); + if (header.magic != LANG_MAGIC) + { + printf_P(_n("NG!\n")); + break; + } + printf_P(_n("OK\n")); + printf_P(_n(" _lt_magic = 0x%08lx %S\n"), header.magic, (header.magic==LANG_MAGIC)?_n("OK"):_n("NA")); + printf_P(_n(" _lt_size = 0x%04x (%d)\n"), header.size, header.size); + printf_P(_n(" _lt_count = 0x%04x (%d)\n"), header.count, header.count); + printf_P(_n(" _lt_chsum = 0x%04x\n"), header.checksum); + printf_P(_n(" _lt_code = 0x%04x\n"), header.code); + printf_P(_n(" _lt_resv1 = 0x%08lx\n"), header.reserved1); + + addr += header.size; + codes[count] = header.code; + count ++; + } + return count; +} + +void list_sec_lang_from_external_flash() +{ + uint16_t codes[8]; + uint8_t count = lang_xflash_enum_codes(codes); + printf_P(_n("XFlash lang count = %hhd\n"), count); +} + +#endif //W25X20CL + + // "Setup" function is called by the Arduino framework on startup. // Before startup, the Timers-functions (PWM)/Analog RW and HardwareSerial provided by the Arduino-code // are initialized by the main() routine provided by the Arduino framework. void setup() { +#ifdef NEW_SPI + spi_init(); +#endif //NEW_SPI + lcd_init(); fdev_setup_stream(lcdout, lcd_putchar, NULL, _FDEV_SETUP_WRITE); //setup lcdout stream @@ -1157,9 +1205,6 @@ void setup() #endif //TMC2130 -#ifdef NEW_SPI - spi_init(); -#endif //NEW_SPI st_init(); // Initialize stepper, this enables interrupts! @@ -1303,16 +1348,35 @@ void setup() // If they differ, an update procedure may need to be performed. At the end of this block, the current firmware version // is being written into the EEPROM, so the update procedure will be triggered only once. + spi_setup(TMC2130_SPCR, TMC2130_SPSR); + puts_P(_n("w25x20cl init: ")); + if (w25x20cl_ini()) + { + uint8_t uid[8]; // 64bit unique id + w25x20cl_rd_uid(uid); + puts_P(_n("OK, UID=")); + for (uint8_t i = 0; i < 8; i ++) + printf_P(PSTR("%02hhx"), uid[i]); + putchar('\n'); + list_sec_lang_from_external_flash(); + } + else + puts_P(_n("NG!\n")); + + lang_selected = eeprom_read_byte((uint8_t*)EEPROM_LANG); if (lang_selected >= LANG_NUM) { - lcd_mylang(); +// lcd_mylang(); + lang_selected = 0; } lang_select(lang_selected); uint16_t sec_lang_code=lang_get_code(1); printf_P(_n("SEC_LANG_CODE=0x%04x (%c%c)\n"), sec_lang_code, sec_lang_code >> 8, sec_lang_code & 0xff); + + #ifdef DEBUG_SEC_LANG lang_print_sec_lang(uartout); #endif //DEBUG_SEC_LANG diff --git a/Firmware/config.h b/Firmware/config.h index 6839dd17..9902349f 100644 --- a/Firmware/config.h +++ b/Firmware/config.h @@ -18,6 +18,9 @@ #define TMC2130_SPCR SPI_SPCR(TMC2130_SPI_RATE, 1, 1, 1, 0) #define TMC2130_SPSR SPI_SPSR(TMC2130_SPI_RATE) +//W25X20CL configuration +#define W25X20CL_PIN_CS 32 + //LANG - Multi-language support //#define LANG_MODE 0 // primary language only #define LANG_MODE 1 // sec. language support diff --git a/Firmware/language.c b/Firmware/language.c index 3f962758..3927c8d0 100644 --- a/Firmware/language.c +++ b/Firmware/language.c @@ -4,54 +4,44 @@ #include "bootapp.h" -// Currectly active language selection. +#ifdef W25X20CL +#include "w25x20cl.h" +#endif //W25X20CL + +// Currently active language selection. uint8_t lang_selected = 0; + #if (LANG_MODE == 0) //primary language only -#else //(LANG_MODE == 0) + +uint8_t lang_select(uint8_t lang) { return 0; } +uint8_t lang_get_count() { return 1; } +uint16_t lang_get_code(uint8_t lang) { return LANG_CODE_EN; } +const char* lang_get_name_by_code(uint16_t code) { return _n("English"); } + +#else //(LANG_MODE == 0) //secondary languages in progmem or xflash + //reserved xx kbytes for secondary language table const char _SEC_LANG[LANG_SIZE_RESERVED] PROGMEM_I2 = "_SEC_LANG"; -#endif //(LANG_MODE == 0) - -//lang_table_header_t structure - (size= 16byte) -typedef struct -{ - uint32_t magic; //+0 - uint16_t size; //+4 - uint16_t count; //+6 - uint16_t checksum; //+8 - uint16_t code; //+10 - uint32_t reserved1; //+12 -} lang_table_header_t; - -//lang_table_t structure - (size= 16byte + 2*count) -typedef struct -{ - lang_table_header_t header; - uint16_t table[]; -} lang_table_t; //lang_table pointer lang_table_t* lang_table = 0; - const char* lang_get_translation(const char* s) { - if (lang_selected == 0) return s + 2; //primary language selected - if (lang_table == 0) return s + 2; //sec. lang table not found + if (lang_selected == 0) return s + 2; //primary language selected, return orig. str. + if (lang_table == 0) return s + 2; //sec. lang table not found, return orig. str. uint16_t ui = pgm_read_word(((uint16_t*)s)); //read string id - if (ui == 0xffff) return s + 2; //translation not found + if (ui == 0xffff) return s + 2; //translation not found, return orig. str. ui = pgm_read_word(((uint16_t*)(((char*)lang_table + 16 + ui*2)))); //read relative offset - if (pgm_read_byte(((uint8_t*)((char*)lang_table + ui))) == 0) - return s + 2;//not translated string + if (pgm_read_byte(((uint8_t*)((char*)lang_table + ui))) == 0) //read first character + return s + 2;//zero length string == not translated, return orig. str. return (const char*)((char*)lang_table + ui); //return calculated pointer } const char* lang_get_sec_lang_str(const char* s) { - uint16_t ui = (uint16_t)&_SEC_LANG; //pointer to _SEC_LANG reserved space - ui += 0x00ff; //add 1 page - ui &= 0xff00; //align to page + uint16_t ui = ((((uint16_t)&_SEC_LANG) + 0x00ff) & 0xff00); //table pointer lang_table_t* _lang_table = ui; //table pointer ui = pgm_read_word(((uint16_t*)s)); //read string id if (ui == 0xffff) return s + 2; //translation not found @@ -59,69 +49,108 @@ const char* lang_get_sec_lang_str(const char* s) return (const char*)((char*)_lang_table + ui); //return calculated pointer } -const char* lang_get_sec_lang_str_by_id(uint16_t id) +uint8_t lang_select(uint8_t lang) { - uint16_t ui = ((((uint16_t)&_SEC_LANG) + 0x00ff) & 0xff00); //table pointer - return ui + pgm_read_word(((uint16_t*)(ui + 16 + id * 2))); //read relative offset and return calculated pointer -} - -const char* lang_select(uint8_t lang) -{ -#if (LANG_MODE == 0) //primary language only - return 0; -#else //(LANG_MODE == 0) - if (lang == 0) //primary language + if (lang == LANG_ID_PRI) //primary language { lang_table = 0; lang_selected = 0; - return; + return 1; } + if (lang == LANG_ID_SEC) //current secondary language + { + uint16_t ui = ((((uint16_t)&_SEC_LANG) + 0x00ff) & 0xff00); //table pointer + if (pgm_read_dword(((uint32_t*)(ui + 0))) != LANG_MAGIC) return 0; //magic not valid + lang_table = ui; // set table pointer + lang_selected = 1; // set language id + return 1; + } +/* uint16_t ui = (uint16_t)&_SEC_LANG; //pointer to _SEC_LANG reserved space ui += 0x00ff; //add 1 page ui &= 0xff00; //align to page lang_table = ui; //set table pointer ui = pgm_read_word(((uint16_t*)(((char*)lang_table + 16)))); //read relative offset of first string (language name) return (const char*)((char*)lang_table + ui); //return calculated pointer -#endif //(LANG_MODE == 0) +*/ } uint8_t lang_get_count() { - uint16_t ui = (uint16_t)&_SEC_LANG; //pointer to _SEC_LANG reserved space - ui += 0x00ff; //add 1 page - ui &= 0xff00; //align to page - lang_table_t* _lang_table = ui; //table pointer - if (pgm_read_dword(((uint32_t*)(_lang_table + 0))) == LANG_MAGIC) return 2; - return 1; -} - -const char* lang_get_name(uint8_t lang) -{ - if (lang == LANG_ID_UNDEFINED) lang = lang_selected; - if (lang == LANG_ID_PRI) return MSG_LANGUAGE_NAME + 2; - if (lang == LANG_ID_SEC) +//#ifdef W25X20CL + uint8_t count = 1; //count = 1+n (primary + all in xflash) + uint32_t addr = 0x00000; //start of xflash + lang_table_header_t header; //table header structure + while (1) { - uint16_t ui = ((((uint16_t)&_SEC_LANG) + 0x00ff) & 0xff00); //table pointer - if (pgm_read_dword(((uint32_t*)(ui + 0))) == LANG_MAGIC) //magic num is OK - return lang_get_sec_lang_str(MSG_LANGUAGE_NAME); + w25x20cl_rd_data(addr, (uint8_t*)&header, sizeof(lang_table_header_t)); //read table header from xflash + if (header.magic != LANG_MAGIC) break; //break if magic not valid + addr += header.size; //calc address of next table + count++; //inc counter } - return 0; + return count; } uint16_t lang_get_code(uint8_t lang) { - if (lang == LANG_ID_UNDEFINED) lang = lang_selected; - if (lang == LANG_ID_PRI) return LANG_CODE_EN; + if (lang == LANG_ID_PRI) return LANG_CODE_EN; //primary lang = EN if (lang == LANG_ID_SEC) { uint16_t ui = ((((uint16_t)&_SEC_LANG) + 0x00ff) & 0xff00); //table pointer - if (pgm_read_dword(((uint32_t*)(ui + 0))) == LANG_MAGIC) //magic num is OK - return pgm_read_word(((uint16_t*)(ui + 10))); //read language code + if (pgm_read_dword(((uint32_t*)(ui + 0))) != LANG_MAGIC) return LANG_CODE_XX; //magic not valid + return pgm_read_word(((uint32_t*)(ui + 10))); //return lang code from progmem } + uint32_t addr = 0x00000; //start of xflash + lang_table_header_t header; //table header structure + lang--; + while (1) + { + w25x20cl_rd_data(addr, (uint8_t*)&header, sizeof(lang_table_header_t)); //read table header from xflash + if (header.magic != LANG_MAGIC) break; //break if not valid + if (--lang == 0) return header.code; + addr += header.size; //calc address of next table + } + +// if (lang == LANG_ID_SEC) +// { +// uint16_t ui = ((((uint16_t)&_SEC_LANG) + 0x00ff) & 0xff00); //table pointer +// if (pgm_read_dword(((uint32_t*)(ui + 0))) == LANG_MAGIC) //magic num is OK +// return pgm_read_word(((uint16_t*)(ui + 10))); //read language code +// } return LANG_CODE_XX; } +const char* lang_get_name_by_code(uint16_t code) +{ + switch (code) + { + case LANG_CODE_EN: return _n("English"); + case LANG_CODE_CZ: return _n("Cestina"); + case LANG_CODE_DE: return _n("Deutsch"); + case LANG_CODE_ES: return _n("Espanol"); + case LANG_CODE_IT: return _n("Italiano"); + case LANG_CODE_PL: return _n("Polski"); + } + return _n("??"); + +// if (lang == LANG_ID_UNDEFINED) lang = lang_selected; +// if (lang == LANG_ID_PRI) return _T(MSG_LANGUAGE_NAME + 2); +// if (lang == LANG_ID_SEC) +// { +// uint16_t ui = ((((uint16_t)&_SEC_LANG) + 0x00ff) & 0xff00); //table pointer +// if (pgm_read_dword(((uint32_t*)(ui + 0))) == LANG_MAGIC) //magic num is OK +// return lang_get_sec_lang_str(MSG_LANGUAGE_NAME); +// } +// return 0; +} + #ifdef DEBUG_SEC_LANG +const char* lang_get_sec_lang_str_by_id(uint16_t id) +{ + uint16_t ui = ((((uint16_t)&_SEC_LANG) + 0x00ff) & 0xff00); //table pointer + return ui + pgm_read_word(((uint16_t*)(ui + 16 + id * 2))); //read relative offset and return calculated pointer +} + uint16_t lang_print_sec_lang(FILE* out) { printf_P(_n("&_SEC_LANG = 0x%04x\n"), &_SEC_LANG); @@ -149,6 +178,7 @@ uint16_t lang_print_sec_lang(FILE* out) } #endif //DEBUG_SEC_LANG +#endif //(LANG_MODE == 0) -const char MSG_LANGUAGE_NAME[] PROGMEM_I1 = ISTR("English"); ////c=0 r=0 +//const char MSG_LANGUAGE_NAME[] PROGMEM_I1 = ISTR("English"); ////c=0 r=0 diff --git a/Firmware/language.h b/Firmware/language.h index e41f7cb8..24cc510d 100644 --- a/Firmware/language.h +++ b/Firmware/language.h @@ -2,15 +2,15 @@ #ifndef LANGUAGE_H #define LANGUAGE_H +#define W25X20CL + #include "config.h" #include -#include +//#include #define PROTOCOL_VERSION "1.0" -#ifdef CUSTOM_MENDEL_NAME - // #define CUSTOM_MENDEL_NAME CUSTOM_MENDEL_NAME -#else +#ifndef CUSTOM_MENDEL_NAME #define MACHINE_NAME "Mendel" #endif @@ -44,6 +44,23 @@ #define _N(s) (__extension__({static const char __c[] PROGMEM_N1 = s; &__c[0];})) #define _n(s) _N(s) +//lang_table_header_t structure - (size= 16byte) +typedef struct +{ + uint32_t magic; //+0 + uint16_t size; //+4 + uint16_t count; //+6 + uint16_t checksum; //+8 + uint16_t code; //+10 + uint32_t reserved1; //+12 +} lang_table_header_t; + +//lang_table_t structure - (size= 16byte + 2*count) +typedef struct +{ + lang_table_header_t header; + uint16_t table[]; +} lang_table_t; // Language indices into their particular symbol tables. #define LANG_ID_PRI 0 @@ -82,21 +99,23 @@ extern uint8_t lang_selected; #if (LANG_MODE != 0) extern const char _SEC_LANG[LANG_SIZE_RESERVED]; -#endif //(LANG_MODE == 0) - extern const char* lang_get_translation(const char* s); extern const char* lang_get_sec_lang_str(const char* s); -extern const char* lang_get_sec_lang_str_by_id(uint16_t id); -extern const char* lang_select(uint8_t lang); +#endif //(LANG_MODE != 0) + +//selects +extern uint8_t lang_select(uint8_t lang); + +//get total number of languages (primary + all in xflash) extern uint8_t lang_get_count(); -extern const char* lang_get_name(uint8_t lang); extern uint16_t lang_get_code(uint8_t lang); +extern const char* lang_get_name_by_code(uint16_t code); #ifdef DEBUG_SEC_LANG +extern const char* lang_get_sec_lang_str_by_id(uint16_t id); extern uint16_t lang_print_sec_lang(FILE* out); #endif //DEBUG_SEC_LANG - #if defined(__cplusplus) } #endif //defined(__cplusplus) @@ -104,7 +123,8 @@ extern uint16_t lang_print_sec_lang(FILE* out); #define CAT2(_s1, _s2) _s1 #define CAT4(_s1, _s2, _s3, _s4) _s1 -extern const char MSG_LANGUAGE_NAME[]; +//Localized language name +//extern const char MSG_LANGUAGE_NAME[]; #include "messages.h" diff --git a/Firmware/pins_Einsy_1_0.h b/Firmware/pins_Einsy_1_0.h index 0267b3fc..35b14dd4 100644 --- a/Firmware/pins_Einsy_1_0.h +++ b/Firmware/pins_Einsy_1_0.h @@ -15,6 +15,7 @@ #define AMBIENT_THERMISTOR #define PINDA_THERMISTOR +#define W25X20CL // external 256kB flash #define SWI2C // enable software i2c #define SWI2C_A8 // 8bit address functions diff --git a/Firmware/spi.h b/Firmware/spi.h index a144a153..bc891810 100644 --- a/Firmware/spi.h +++ b/Firmware/spi.h @@ -15,7 +15,11 @@ #define DD_MOSI 2 #define DD_MISO 3 -inline void spi_init() +#if defined(__cplusplus) +extern "C" { +#endif //defined(__cplusplus) + +static inline void spi_init() { DDRB &= ~((1 << DD_SCK) | (1 << DD_MOSI) | (1 << DD_MISO)); DDRB |= (1 << DD_SS) | (1 << DD_SCK) | (1 << DD_MOSI); @@ -25,17 +29,21 @@ inline void spi_init() SPSR = 0x00; } -inline void spi_setup(uint8_t spcr, uint8_t spsr) +static inline void spi_setup(uint8_t spcr, uint8_t spsr) { SPCR = spcr; SPSR = spsr; } -inline uint8_t spi_txrx(uint8_t tx) +static inline uint8_t spi_txrx(uint8_t tx) { SPDR = tx; while (!(SPSR & (1 << SPIF))); return SPDR; } +#if defined(__cplusplus) +} +#endif //defined(__cplusplus) + #endif //SPI_H diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index fd79995a..14d2792a 100644 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -3715,14 +3715,18 @@ static void lcd_crash_mode_set() #endif //TMC2130 -static void lcd_set_lang(unsigned char lang) { - lang_selected = lang; - firstrun = 1; - eeprom_update_byte((unsigned char *)EEPROM_LANG, lang); - /*langsel=0;*/ - if (langsel == LANGSEL_MODAL) - // From modal mode to an active mode? This forces the menu to return to the setup menu. - langsel = LANGSEL_ACTIVE; +static void lcd_set_lang(unsigned char lang) +{ + lang_select(lang); +/* + lang_selected = lang; + firstrun = 1; + eeprom_update_byte((unsigned char *)EEPROM_LANG, lang); + // langsel=0; + if (langsel == LANGSEL_MODAL) + // From modal mode to an active mode? This forces the menu to return to the setup menu. + langsel = LANGSEL_ACTIVE; +*/ } #ifdef PAT9125 @@ -3756,17 +3760,21 @@ void lcd_force_language_selection() { eeprom_update_byte((unsigned char *)EEPROM_LANG, LANG_ID_FORCE_SELECTION); } +#if (LANG_MODE != 0) static void lcd_language_menu() { - START_MENU(); - if (langsel == LANGSEL_OFF) - MENU_ITEM(back, _T(MSG_SETTINGS), 0); - else if (langsel == LANGSEL_ACTIVE) - MENU_ITEM(back, _T(MSG_WATCH), 0); - for (int i=0; i < lang_get_count(); i++) - MENU_ITEM(setlang, lang_get_name(i), i); - END_MENU(); + START_MENU(); + if (langsel == LANGSEL_OFF) + MENU_ITEM(back, _T(MSG_SETTINGS), 0); + else if (langsel == LANGSEL_ACTIVE) + MENU_ITEM(back, _T(MSG_WATCH), 0); + MENU_ITEM(setlang, lang_get_name_by_code(lang_get_code(0)), 0); + for (int i = 1; i < lang_get_count(); i++) + MENU_ITEM(setlang, lang_get_name_by_code(lang_get_code(i+1)), i); + END_MENU(); } +#endif //(LANG_MODE != 0) + void lcd_mesh_bedleveling() { @@ -4232,7 +4240,10 @@ static void lcd_settings_menu() { MENU_ITEM(submenu, _T(MSG_BABYSTEP_Z), lcd_babystep_z); } + +#if (LANG_MODE != 0) MENU_ITEM(submenu, _i("Select language"), lcd_language_menu);////MSG_LANGUAGE_SELECT c=0 r=0 +#endif //(LANG_MODE != 0) if (card.ToshibaFlashAir_isEnabled()) { MENU_ITEM(function, _i("SD card [FlshAir]"), lcd_toshiba_flash_air_compatibility_toggle);////MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON c=19 r=1 @@ -4591,7 +4602,7 @@ void lcd_mylang_drawmenu(int cursor) { } } */ - +/* void lcd_mylang_drawmenu(int cursor) { unsigned char lang_cnt = lang_get_count(); @@ -4642,7 +4653,8 @@ void lcd_mylang_drawmenu(int cursor) lcd.print("^"); } } - +*/ +/* void lcd_mylang_drawcursor(int cursor) { unsigned char lang_cnt = lang_get_count(); @@ -4652,8 +4664,9 @@ void lcd_mylang_drawcursor(int cursor) { lcd.print(">"); -} - +} +*/ +/* void lcd_mylang() { int enc_dif = 0; @@ -4710,15 +4723,13 @@ void lcd_mylang() delay(500); } - /* - if (++counter == 80) { - hlaska++; - if(hlaska>LANG_NUM) hlaska=1; - lcd_mylang_top(hlaska); - lcd_mylang_drawcursor(cursor_pos); - counter=0; - } - */ +// if (++counter == 80) { +// hlaska++; +// if(hlaska>LANG_NUM) hlaska=1; +// lcd_mylang_top(hlaska); +// lcd_mylang_drawcursor(cursor_pos); +// counter=0; +// } }; if(MYSERIAL.available() > 1){ @@ -4731,7 +4742,7 @@ void lcd_mylang() lcd_return_to_status(); } - +*/ void bowden_menu() { int enc_dif = encoderDiff; int cursor_pos = 0; diff --git a/Firmware/ultralcd.h b/Firmware/ultralcd.h index 4107bc72..a21e35a4 100644 --- a/Firmware/ultralcd.h +++ b/Firmware/ultralcd.h @@ -32,7 +32,7 @@ void prusa_statistics(int _message, uint8_t _col_nr = 0); void lcd_confirm_print(); unsigned char lcd_choose_color(); -void lcd_mylang(); +//void lcd_mylang(); bool lcd_detected(void); static void lcd_selftest_v(); diff --git a/Firmware/w25x20cl.c b/Firmware/w25x20cl.c new file mode 100644 index 00000000..04f0d402 --- /dev/null +++ b/Firmware/w25x20cl.c @@ -0,0 +1,178 @@ +//w25x20cl.c + +#include "w25x20cl.h" +#include +#include +#include "io_atmega2560.h" +#include "spi.h" + +#define _MFRID 0xEF +#define _DEVID 0x11 + +#define _CMD_ENABLE_WR 0x06 +#define _CMD_ENABLE_WR_VSR 0x50 +#define _CMD_DISABLE_WR 0x04 +#define _CMD_RD_STATUS_REG 0x05 +#define _CMD_WR_STATUS_REG 0x01 +#define _CMD_RD_DATA 0x03 +#define _CMD_RD_FAST 0x0b +#define _CMD_RD_FAST_D_O 0x3b +#define _CMD_RD_FAST_D_IO 0xbb +#define _CMD_PAGE_PROGRAM 0x02 +#define _CMD_SECTOR_ERASE 0x20 +#define _CMD_BLOCK32_ERASE 0x52 +#define _CMD_BLOCK64_ERASE 0xd8 +#define _CMD_CHIP_ERASE 0xc7 +#define _CMD_CHIP_ERASE2 0x60 +#define _CMD_PWR_DOWN 0xb9 +#define _CMD_PWR_DOWN_REL 0xab +#define _CMD_MFRID_DEVID 0x90 +#define _CMD_MFRID_DEVID_D 0x92 +#define _CMD_JEDEC_ID 0x9f +#define _CMD_RD_UID 0x4b + +#define _CS_LOW() PORT(W25X20CL_PIN_CS) &= ~__MSK(W25X20CL_PIN_CS) +#define _CS_HIGH() PORT(W25X20CL_PIN_CS) |= __MSK(W25X20CL_PIN_CS) + +//#define _SPI_TX swspi_tx +//#define _SPI_RX swspi_rx +#define _SPI_TX(b) spi_txrx(b) +#define _SPI_RX() spi_txrx(0xff) + + +int w25x20cl_mfrid_devid(void); + + +int8_t w25x20cl_ini(void) +{ + PIN_OUT(W25X20CL_PIN_CS); + _CS_HIGH(); + if (!w25x20cl_mfrid_devid()) return 0; + return 1; +} + +void w25x20cl_enable_wr(void) +{ + _CS_LOW(); + _SPI_TX(_CMD_ENABLE_WR); // send command 0x06 + _CS_HIGH(); +} + +void w25x20cl_disable_wr(void) +{ + _CS_LOW(); + _SPI_TX(_CMD_DISABLE_WR); // send command 0x04 + _CS_HIGH(); +} + +uint8_t w25x20cl_rd_status_reg(void) +{ + _CS_LOW(); + _SPI_TX(_CMD_RD_STATUS_REG); // send command 0x90 + uint8_t val = _SPI_RX(); // receive value + _CS_HIGH(); + return val; +} + +void w25x20cl_wr_status_reg(uint8_t val) +{ + _CS_LOW(); + _SPI_TX(_CMD_WR_STATUS_REG); // send command 0x90 + _SPI_TX(val); // send value + _CS_HIGH(); +} + +void w25x20cl_rd_data(uint32_t addr, uint8_t* data, uint16_t cnt) +{ + _CS_LOW(); + _SPI_TX(_CMD_RD_DATA); // send command 0x03 + _SPI_TX(((uint8_t*)&addr)[2]); // send addr bits 16..23 + _SPI_TX(((uint8_t*)&addr)[1]); // send addr bits 8..15 + _SPI_TX(((uint8_t*)&addr)[0]); // send addr bits 0..7 + while (cnt--) // receive data + *(data++) = _SPI_RX(); + _CS_HIGH(); +} + +void w25x20cl_page_program(uint32_t addr, uint8_t* data, uint16_t cnt) +{ + _CS_LOW(); + _SPI_TX(_CMD_PAGE_PROGRAM); // send command 0x02 + _SPI_TX(((uint8_t*)&addr)[2]); // send addr bits 16..23 + _SPI_TX(((uint8_t*)&addr)[1]); // send addr bits 8..15 + _SPI_TX(((uint8_t*)&addr)[0]); // send addr bits 0..7 + while (cnt--) // send data + _SPI_TX(*(data++)); + _CS_HIGH(); +} + +void w25x20cl_page_program_P(uint32_t addr, uint8_t* data, uint16_t cnt) +{ + _CS_LOW(); + _SPI_TX(_CMD_PAGE_PROGRAM); // send command 0x02 + _SPI_TX(((uint8_t*)&addr)[2]); // send addr bits 16..23 + _SPI_TX(((uint8_t*)&addr)[1]); // send addr bits 8..15 + _SPI_TX(((uint8_t*)&addr)[0]); // send addr bits 0..7 + while (cnt--) // send data + _SPI_TX(pgm_read_byte(data++)); + _CS_HIGH(); +} + +void w25x20cl_erase(uint8_t cmd, uint32_t addr) +{ + _CS_LOW(); + _SPI_TX(_CMD_SECTOR_ERASE); // send command 0x20 + _SPI_TX(((uint8_t*)&addr)[2]); // send addr bits 16..23 + _SPI_TX(((uint8_t*)&addr)[1]); // send addr bits 8..15 + _SPI_TX(((uint8_t*)&addr)[0]); // send addr bits 0..7 + _CS_HIGH(); +} + +void w25x20cl_sector_erase(uint32_t addr) +{ + return w25x20cl_erase(_CMD_SECTOR_ERASE, addr); +} + +void w25x20cl_block32_erase(uint32_t addr) +{ + return w25x20cl_erase(_CMD_BLOCK32_ERASE, addr); +} + +void w25x20cl_block64_erase(uint32_t addr) +{ + return w25x20cl_erase(_CMD_BLOCK64_ERASE, addr); +} + +void w25x20cl_chip_erase(void) +{ + _CS_LOW(); + _SPI_TX(_CMD_CHIP_ERASE); // send command 0xc7 + _CS_HIGH(); +} + + +void w25x20cl_rd_uid(uint8_t* uid) +{ + _CS_LOW(); + _SPI_TX(_CMD_RD_UID); // send command 0x4b + uint8_t cnt = 4; // 4 dummy bytes + while (cnt--) // receive dummy bytes + _SPI_RX(); + cnt = 8; // 8 bytes UID + while (cnt--) // receive UID + uid[7 - cnt] = _SPI_RX(); + _CS_HIGH(); +} + +int w25x20cl_mfrid_devid(void) +{ + _CS_LOW(); + _SPI_TX(_CMD_MFRID_DEVID); // send command 0x90 + uint8_t cnt = 3; // 3 address bytes + while (cnt--) // send address bytes + _SPI_TX(0x00); + uint8_t w25x20cl_mfrid = _SPI_RX(); // receive mfrid + uint8_t w25x20cl_devid = _SPI_RX(); // receive devid + _CS_HIGH(); + return ((w25x20cl_mfrid == _MFRID) && (w25x20cl_devid == _DEVID)); +} diff --git a/Firmware/w25x20cl.h b/Firmware/w25x20cl.h new file mode 100644 index 00000000..72a0ddde --- /dev/null +++ b/Firmware/w25x20cl.h @@ -0,0 +1,40 @@ +//w25x20cl.h +#ifndef _W25X20CL_H +#define _W25X20CL_H + +#include +#include "config.h" + + +#define W25_STATUS_BUSY 0x01 +#define W25_STATUS_WEL 0x02 +#define W25_STATUS_BP0 0x04 +#define W25_STATUS_BP1 0x08 +#define W25_STATUS_TB 0x20 +#define W25_STATUS_SRP 0x80 + + +#if defined(__cplusplus) +extern "C" { +#endif //defined(__cplusplus) + + +extern int8_t w25x20cl_ini(void); +extern void w25x20cl_enable_wr(void); +extern void w25x20cl_disable_wr(void); +extern uint8_t w25x20cl_rd_status_reg(void); +extern void w25x20cl_wr_status_reg(uint8_t val); +extern void w25x20cl_rd_data(uint32_t addr, uint8_t* data, uint16_t cnt); +extern void w25x20cl_page_program(uint32_t addr, uint8_t* data, uint16_t cnt); +extern void w25x20cl_page_program_P(uint32_t addr, uint8_t* data, uint16_t cnt); +extern void w25x20cl_sector_erase(uint32_t addr); +extern void w25x20cl_block32_erase(uint32_t addr); +extern void w25x20cl_block64_erase(uint32_t addr); +extern void w25x20cl_chip_erase(void); +extern void w25x20cl_rd_uid(uint8_t* uid); + + +#if defined(__cplusplus) +} +#endif //defined(__cplusplus) +#endif //_W25X20CL_H