From 451f48231d922d473bae27d2f8992857f0bc3fe2 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Fri, 24 Jul 2020 03:09:14 -0500 Subject: [PATCH] Ender 3 V2 BL24C16 EEPROM support (#18758) --- Marlin/src/HAL/STM32F1/eeprom_bl24cxx.cpp | 81 ++++++ Marlin/src/HAL/STM32F1/eeprom_if_iic.cpp | 51 ++++ Marlin/src/HAL/shared/eeprom_api.h | 20 +- Marlin/src/MarlinCore.cpp | 4 +- Marlin/src/gcode/eeprom/M500-M504.cpp | 36 +++ Marlin/src/inc/Conditionals_post.h | 3 + Marlin/src/inc/SanityCheck.h | 9 +- Marlin/src/lcd/dwin/dwin.cpp | 9 +- Marlin/src/lcd/dwin/dwin.h | 2 +- Marlin/src/lcd/dwin/eeprom_BL24CXX.cpp | 263 ----------------- Marlin/src/libs/BL24CXX.cpp | 273 ++++++++++++++++++ .../dwin/eeprom_BL24CXX.h => libs/BL24CXX.h} | 36 +-- Marlin/src/libs/hex_print_routines.cpp | 2 +- Marlin/src/pins/stm32f1/pins_CREALITY_V4.h | 8 +- buildroot/tests/STM32F103RET6_creality-tests | 1 + 15 files changed, 495 insertions(+), 303 deletions(-) create mode 100644 Marlin/src/HAL/STM32F1/eeprom_bl24cxx.cpp create mode 100644 Marlin/src/HAL/STM32F1/eeprom_if_iic.cpp delete mode 100644 Marlin/src/lcd/dwin/eeprom_BL24CXX.cpp create mode 100644 Marlin/src/libs/BL24CXX.cpp rename Marlin/src/{lcd/dwin/eeprom_BL24CXX.h => libs/BL24CXX.h} (65%) diff --git a/Marlin/src/HAL/STM32F1/eeprom_bl24cxx.cpp b/Marlin/src/HAL/STM32F1/eeprom_bl24cxx.cpp new file mode 100644 index 0000000000..f77306a88a --- /dev/null +++ b/Marlin/src/HAL/STM32F1/eeprom_bl24cxx.cpp @@ -0,0 +1,81 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * 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 3 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, see . + * + */ + +/** + * PersistentStore for Arduino-style EEPROM interface + * with simple implementations supplied by Marlin. + */ + +#include "../../inc/MarlinConfig.h" + +#if ENABLED(IIC_BL24CXX_EEPROM) + +#include "../shared/eeprom_if.h" +#include "../shared/eeprom_api.h" + +// +// PersistentStore +// + +#ifndef MARLIN_EEPROM_SIZE + #error "MARLIN_EEPROM_SIZE is required for IIC_BL24CXX_EEPROM." +#endif + +size_t PersistentStore::capacity() { return MARLIN_EEPROM_SIZE; } + +bool PersistentStore::access_start() { eeprom_init(); return true; } +bool PersistentStore::access_finish() { return true; } + +bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) { + while (size--) { + uint8_t v = *value; + uint8_t * const p = (uint8_t * const)pos; + // EEPROM has only ~100,000 write cycles, + // so only write bytes that have changed! + if (v != eeprom_read_byte(p)) { + eeprom_write_byte(p, v); + delay(2); + if (eeprom_read_byte(p) != v) { + SERIAL_ECHO_MSG(STR_ERR_EEPROM_WRITE); + return true; + } + } + crc16(crc, &v, 1); + pos++; + value++; + } + return false; +} + +bool PersistentStore::read_data(int &pos, uint8_t* value, size_t size, uint16_t *crc, const bool writing/*=true*/) { + do { + uint8_t * const p = (uint8_t * const)pos; + uint8_t c = eeprom_read_byte(p); + if (writing) *value = c; + crc16(crc, &c, 1); + pos++; + value++; + } while (--size); + return false; +} + +#endif // IIC_BL24CXX_EEPROM diff --git a/Marlin/src/HAL/STM32F1/eeprom_if_iic.cpp b/Marlin/src/HAL/STM32F1/eeprom_if_iic.cpp new file mode 100644 index 0000000000..33dd277add --- /dev/null +++ b/Marlin/src/HAL/STM32F1/eeprom_if_iic.cpp @@ -0,0 +1,51 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * 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 3 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, see . + * + */ + +/** + * Platform-independent Arduino functions for I2C EEPROM. + * Enable USE_SHARED_EEPROM if not supplied by the framework. + */ + +#include "../../inc/MarlinConfig.h" + +#if ENABLED(IIC_BL24CXX_EEPROM) + +#include "../../libs/BL24CXX.h" +#include "../shared/eeprom_if.h" + +void eeprom_init() { BL24CXX::init(); } + +// ------------------------ +// Public functions +// ------------------------ + +void eeprom_write_byte(uint8_t *pos, unsigned char value) { + const unsigned eeprom_address = (unsigned)pos; + return BL24CXX::writeOneByte(eeprom_address, value); +} + +uint8_t eeprom_read_byte(uint8_t *pos) { + const unsigned eeprom_address = (unsigned)pos; + return BL24CXX::readOneByte(eeprom_address); +} + +#endif // IIC_BL24CXX_EEPROM diff --git a/Marlin/src/HAL/shared/eeprom_api.h b/Marlin/src/HAL/shared/eeprom_api.h index b97267484e..6445f7a4aa 100644 --- a/Marlin/src/HAL/shared/eeprom_api.h +++ b/Marlin/src/HAL/shared/eeprom_api.h @@ -29,20 +29,38 @@ class PersistentStore { public: + + // Total available persistent storage space (in bytes) + static size_t capacity(); + + // Prepare to read or write static bool access_start(); + + // Housecleaning after read or write static bool access_finish(); + + // Write one or more bytes of data and update the CRC + // Return 'true' on write error static bool write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc); + + // Read one or more bytes of data and update the CRC + // Return 'true' on read error static bool read_data(int &pos, uint8_t* value, size_t size, uint16_t *crc, const bool writing=true); - static size_t capacity(); + // Write one or more bytes of data + // Return 'true' on write error static inline bool write_data(const int pos, const uint8_t* value, const size_t size=sizeof(uint8_t)) { int data_pos = pos; uint16_t crc = 0; return write_data(data_pos, value, size, &crc); } + // Write a single byte of data + // Return 'true' on write error static inline bool write_data(const int pos, const uint8_t value) { return write_data(pos, &value); } + // Read one or more bytes of data + // Return 'true' on read error static inline bool read_data(const int pos, uint8_t* value, const size_t size=1) { int data_pos = pos; uint16_t crc = 0; diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp index 55c0bda4ac..7ba577504a 100644 --- a/Marlin/src/MarlinCore.cpp +++ b/Marlin/src/MarlinCore.cpp @@ -72,7 +72,7 @@ #endif #if ENABLED(IIC_BL24CXX_EEPROM) - #include "lcd/dwin/eeprom_BL24CXX.h" + #include "libs/BL24CXX.h" #endif #if ENABLED(DIRECT_STEPPING) @@ -1171,7 +1171,7 @@ void setup() { #if ENABLED(IIC_BL24CXX_EEPROM) BL24CXX::init(); const uint8_t err = BL24CXX::check(); - SERIAL_ECHO_TERNARY(err, "I2C_EEPROM Check ", "failed", "succeeded", "!\n"); + SERIAL_ECHO_TERNARY(err, "BL24CXX Check ", "failed", "succeeded", "!\n"); #endif #if ENABLED(DWIN_CREALITY_LCD) diff --git a/Marlin/src/gcode/eeprom/M500-M504.cpp b/Marlin/src/gcode/eeprom/M500-M504.cpp index 4eb6dfcc76..5aee68ba99 100644 --- a/Marlin/src/gcode/eeprom/M500-M504.cpp +++ b/Marlin/src/gcode/eeprom/M500-M504.cpp @@ -58,11 +58,47 @@ void GcodeSuite::M502() { #endif // !DISABLE_M503 #if ENABLED(EEPROM_SETTINGS) + + #if ENABLED(MARLIN_DEV_MODE) + #include "../../libs/hex_print_routines.h" + #endif + /** * M504: Validate EEPROM Contents */ void GcodeSuite::M504() { + #if ENABLED(MARLIN_DEV_MODE) + const bool dowrite = parser.seenval('W'); + if (dowrite || parser.seenval('R')) { + uint8_t val = 0; + int addr = parser.value_ushort(); + if (dowrite) { + val = parser.byteval('V'); + persistentStore.write_data(addr, &val); + SERIAL_ECHOLNPAIR("Wrote address ", addr, " with ", int(val)); + } + else { + if (parser.seenval('T')) { + const int endaddr = parser.value_ushort(); + while (addr <= endaddr) { + persistentStore.read_data(addr, &val); + SERIAL_ECHOLNPAIR("0x", hex_word(addr), ":", hex_byte(val)); + addr++; + safe_delay(10); + } + SERIAL_EOL(); + } + else { + persistentStore.read_data(addr, &val); + SERIAL_ECHOLNPAIR("Read address ", addr, " and got ", int(val)); + } + } + return; + } + #endif + if (settings.validate()) SERIAL_ECHO_MSG("EEPROM OK"); } + #endif diff --git a/Marlin/src/inc/Conditionals_post.h b/Marlin/src/inc/Conditionals_post.h index 401a64d72d..e12310e07c 100644 --- a/Marlin/src/inc/Conditionals_post.h +++ b/Marlin/src/inc/Conditionals_post.h @@ -50,6 +50,8 @@ #define USE_EMULATED_EEPROM 1 #elif ANY(I2C_EEPROM, SPI_EEPROM) #define USE_WIRED_EEPROM 1 + #elif ENABLED(IIC_BL24CXX_EEPROM) + // nothing #else #define USE_FALLBACK_EEPROM 1 #endif @@ -60,6 +62,7 @@ #undef SDCARD_EEPROM_EMULATION #undef SRAM_EEPROM_EMULATION #undef FLASH_EEPROM_EMULATION + #undef IIC_BL24CXX_EEPROM #endif #ifdef TEENSYDUINO diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index f8e4dc669a..a90571b175 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -2131,8 +2131,13 @@ static_assert(hbm[Z_AXIS] >= 0, "HOMING_BUMP_MM.Z must be greater than or equal */ #if ENABLED(EEPROM_SETTINGS) #if 1 < 0 \ - + ENABLED(I2C_EEPROM) + ENABLED(SPI_EEPROM) + ENABLED(QSPI_EEPROM) \ - + ENABLED(SDCARD_EEPROM_EMULATION) + ENABLED(FLASH_EEPROM_EMULATION) + ENABLED(SRAM_EEPROM_EMULATION) + + ENABLED(I2C_EEPROM) \ + + ENABLED(SPI_EEPROM) \ + + ENABLED(QSPI_EEPROM) \ + + ENABLED(SDCARD_EEPROM_EMULATION) \ + + ENABLED(FLASH_EEPROM_EMULATION) \ + + ENABLED(SRAM_EEPROM_EMULATION) \ + + ENABLED(IIC_BL24CXX_EEPROM) #error "Please select only one method of EEPROM Persistent Storage." #endif #endif diff --git a/Marlin/src/lcd/dwin/dwin.cpp b/Marlin/src/lcd/dwin/dwin.cpp index 4f661ca953..fd2b6810cc 100644 --- a/Marlin/src/lcd/dwin/dwin.cpp +++ b/Marlin/src/lcd/dwin/dwin.cpp @@ -185,10 +185,11 @@ int temphot = 0, tempbed = 0; float zprobe_zoffset = 0; float last_zoffset = 0, last_probe_zoffset = 0; -#define FONT_EEPROM_OFFSET 0 +#define DWIN_LANGUAGE_EEPROM_ADDRESS 0x01 // Between 0x01 and 0x63 (EEPROM_OFFSET-1) + // BL24CXX::check() uses 0x00 void lcd_select_language(void) { - BL24CXX::read(FONT_EEPROM_OFFSET, (uint8_t*)&HMI_flag.language_flag, sizeof(HMI_flag.language_flag)); + BL24CXX::read(DWIN_LANGUAGE_EEPROM_ADDRESS, (uint8_t*)&HMI_flag.language_flag, sizeof(HMI_flag.language_flag)); if (HMI_flag.language_flag) DWIN_JPG_CacheTo1(Language_Chinese); else @@ -198,12 +199,12 @@ void lcd_select_language(void) { void set_english_to_eeprom(void) { HMI_flag.language_flag = 0; DWIN_JPG_CacheTo1(Language_English); - BL24CXX::write(FONT_EEPROM_OFFSET, (uint8_t*)&HMI_flag.language_flag, sizeof(HMI_flag.language_flag)); + BL24CXX::write(DWIN_LANGUAGE_EEPROM_ADDRESS, (uint8_t*)&HMI_flag.language_flag, sizeof(HMI_flag.language_flag)); } void set_chinese_to_eeprom(void) { HMI_flag.language_flag = 1; DWIN_JPG_CacheTo1(Language_Chinese); - BL24CXX::write(FONT_EEPROM_OFFSET, (uint8_t*)&HMI_flag.language_flag, sizeof(HMI_flag.language_flag)); + BL24CXX::write(DWIN_LANGUAGE_EEPROM_ADDRESS, (uint8_t*)&HMI_flag.language_flag, sizeof(HMI_flag.language_flag)); } void show_plus_or_minus(uint8_t size, uint16_t bColor, uint8_t iNum, uint8_t fNum, uint16_t x, uint16_t y, long value) { diff --git a/Marlin/src/lcd/dwin/dwin.h b/Marlin/src/lcd/dwin/dwin.h index e834ef3e24..2d24d2504e 100644 --- a/Marlin/src/lcd/dwin/dwin.h +++ b/Marlin/src/lcd/dwin/dwin.h @@ -27,7 +27,7 @@ #include "dwin_lcd.h" #include "rotary_encoder.h" -#include "eeprom_BL24CXX.h" +#include "../../libs/BL24CXX.h" #include diff --git a/Marlin/src/lcd/dwin/eeprom_BL24CXX.cpp b/Marlin/src/lcd/dwin/eeprom_BL24CXX.cpp deleted file mode 100644 index 25356ab406..0000000000 --- a/Marlin/src/lcd/dwin/eeprom_BL24CXX.cpp +++ /dev/null @@ -1,263 +0,0 @@ -/** - * Marlin 3D Printer Firmware - * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] - * - * Based on Sprinter and grbl. - * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm - * - * 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 3 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, see . - * - */ - -/******************************************************************************** - * @file eeprom_BL24CXX.cpp - * @brief i2c EEPROM for Ender 3 v2 board (4.2.2) - ********************************************************************************/ - -#include "../../inc/MarlinConfig.h" - -#if ENABLED(IIC_BL24CXX_EEPROM) - -#include "eeprom_BL24CXX.h" -#include "../../MarlinCore.h" - -#include - -/******************** IIC ********************/ - -// 初始化IIC -void IIC::init() { - SET_OUTPUT(IIC_EEPROM_SDA); - SET_OUTPUT(IIC_EEPROM_SCL); - - IIC_SCL_1(); - IIC_SDA_1(); -} - -// 产生IIC起始信号 -void IIC::start() { - SDA_OUT(); // sda线输出 - IIC_SDA_1(); - IIC_SCL_1(); - delay_us(4); - IIC_SDA_0(); // START:when CLK is high, DATA change form high to low - delay_us(4); - IIC_SCL_0(); // 钳住I2C总线,准备发送或接收数据 -} - -// 产生IIC停止信号 -void IIC::stop() { - SDA_OUT(); // sda线输出 - IIC_SCL_0(); - IIC_SDA_0(); // STOP:when CLK is high DATA change form low to high - delay_us(4); - IIC_SCL_1(); - IIC_SDA_1(); // 发送I2C总线结束信号 - delay_us(4); -} - -// 等待应答信号到来 -// 返回值:1,接收应答失败 -// 0,接收应答成功 -uint8_t IIC::wait_ack() { - uint8_t ucErrTime=0; - SDA_IN(); // SDA设置为输入 - IIC_SDA_1();delay_us(1); - IIC_SCL_1();delay_us(1); - while (READ_SDA()) { - ucErrTime++; - if (ucErrTime>250) { - stop(); - return 1; - } - } - IIC_SCL_0(); // 时钟输出0 - return 0; -} - -// 产生ACK应答 -void IIC::ack() { - IIC_SCL_0(); - SDA_OUT(); - IIC_SDA_0(); - delay_us(2); - IIC_SCL_1(); - delay_us(2); - IIC_SCL_0(); -} - -// 不产生ACK应答 -void IIC::nAck() { - IIC_SCL_0(); - SDA_OUT(); - IIC_SDA_1(); - delay_us(2); - IIC_SCL_1(); - delay_us(2); - IIC_SCL_0(); -} - -// IIC发送一个字节 -// 返回从机有无应答 -// 1,有应答 -// 0,无应答 -void IIC::send_byte(uint8_t txd) { - SDA_OUT(); - IIC_SCL_0(); // 拉低时钟开始数据传输 - LOOP_L_N(t, 8) { - // IIC_SDA = (txd & 0x80) >> 7; - if (txd & 0x80) IIC_SDA_1(); else IIC_SDA_0(); - txd <<= 1; - delay_us(2); // 对TEA5767这三个延时都是必须的 - IIC_SCL_1(); - delay_us(2); - IIC_SCL_0(); - delay_us(2); - } -} - -// 读1个字节,ack=1时,发送ACK,ack=0,发送nACK -uint8_t IIC::read_byte(unsigned char ack_chr) { - unsigned char receive = 0; - SDA_IN(); // SDA设置为输入 - LOOP_L_N(i, 8) { - IIC_SCL_0(); - delay_us(2); - IIC_SCL_1(); - receive <<= 1; - if (READ_SDA()) receive++; - delay_us(1); - } - ack_chr ? ack() : nAck(); // 发送ACK / 发送nACK - return receive; -} - -/******************** EEPROM ********************/ - -// 初始化IIC接口 -void BL24CXX::init() { IIC::init(); } - -// 在BL24CXX指定地址读出一个数据 -// ReadAddr:开始读数的地址 -// 返回值 :读到的数据 -uint8_t BL24CXX::readOneByte(uint16_t ReadAddr) { - uint8_t temp = 0; - IIC::start(); - if (EE_TYPE > BL24C16) { - IIC::send_byte(0xA0); // 发送写命令 - IIC::wait_ack(); - IIC::send_byte(ReadAddr >> 8); // 发送高地址 - IIC::wait_ack(); - } - else - IIC::send_byte(0xA0 + ((ReadAddr >> 8) << 1)); // 发送器件地址0xA0,写数据 - - IIC::wait_ack(); - IIC::send_byte(ReadAddr & 0xFF); // 发送低地址 - IIC::wait_ack(); - IIC::start(); - IIC::send_byte(0xA1); // 进入接收模式 - IIC::wait_ack(); - temp = IIC::read_byte(0); - IIC::stop(); // 产生一个停止条件 - return temp; -} - -// 在BL24CXX指定地址写入一个数据 -// WriteAddr :写入数据的目的地址 -// DataToWrite:要写入的数据 -void BL24CXX::writeOneByte(uint16_t WriteAddr, uint8_t DataToWrite) { - IIC::start(); - if (EE_TYPE > BL24C16) { - IIC::send_byte(0xA0); // 发送写命令 - IIC::wait_ack(); - IIC::send_byte(WriteAddr >> 8); // 发送高地址 - } - else { - IIC::send_byte(0xA0 + ((WriteAddr >> 8) << 1)); // 发送器件地址0xA0,写数据 - } - IIC::wait_ack(); - IIC::send_byte(WriteAddr & 0xFF); // 发送低地址 - IIC::wait_ack(); - IIC::send_byte(DataToWrite); // 发送字节 - IIC::wait_ack(); - IIC::stop(); // 产生一个停止条件 - delay(10); -} - -// 在BL24CXX里面的指定地址开始写入长度为Len的数据 -// 该函数用于写入16bit或者32bit的数据. -// WriteAddr :开始写入的地址 -// DataToWrite:数据数组首地址 -// Len :要写入数据的长度2,4 -void BL24CXX::writeLenByte(uint16_t WriteAddr, uint32_t DataToWrite, uint8_t Len) { - LOOP_L_N(t, Len) - writeOneByte(WriteAddr + t, (DataToWrite >> (8 * t)) & 0xFF); -} - -// 在BL24CXX里面的指定地址开始读出长度为Len的数据 -// 该函数用于读出16bit或者32bit的数据. -// ReadAddr :开始读出的地址 -// 返回值 :数据 -// Len :要读出数据的长度2,4 -uint32_t BL24CXX::readLenByte(uint16_t ReadAddr, uint8_t Len) { - uint32_t temp = 0; - LOOP_L_N(t, Len) { - temp <<= 8; - temp += readOneByte(ReadAddr + Len - t - 1); - } - return temp; -} - -// 检查BL24CXX是否正常 -// 这里用了24XX的最后一个地址(255)来存储标志字. -// 如果用其他24C系列,这个地址要修改 -// 返回1:检测失败 -// 返回0:检测成功 -uint8_t BL24CXX::check() { - uint8_t temp; - temp = readOneByte(255); // 避免每次开机都写BL24CXX - if (temp == 'U') return 0; - else { // 排除第一次初始化的情况 - writeOneByte(255, 'U'); - temp = readOneByte(255); - if (temp == 'U') return 0; - } - return 1; -} - -// 在BL24CXX里面的指定地址开始读出指定个数的数据 -// ReadAddr :开始读出的地址 对24c02为0~255 -// pBuffer :数据数组首地址 -// NumToRead:要读出数据的个数 -void BL24CXX::read(uint16_t ReadAddr, uint8_t *pBuffer, uint16_t NumToRead) { - while (NumToRead) { - *pBuffer++ = readOneByte(ReadAddr++); - NumToRead--; - } -} - -// 在BL24CXX里面的指定地址开始写入指定个数的数据 -// WriteAddr :开始写入的地址 对24c02为0~255 -// pBuffer :数据数组首地址 -// NumToWrite:要写入数据的个数 -void BL24CXX::write(uint16_t WriteAddr, uint8_t *pBuffer, uint16_t NumToWrite) { - while (NumToWrite--) { - writeOneByte(WriteAddr, *pBuffer); - WriteAddr++; - pBuffer++; - } -} - -#endif // IIC_BL24CXX_EEPROM diff --git a/Marlin/src/libs/BL24CXX.cpp b/Marlin/src/libs/BL24CXX.cpp new file mode 100644 index 0000000000..d34ed8340f --- /dev/null +++ b/Marlin/src/libs/BL24CXX.cpp @@ -0,0 +1,273 @@ +/** + * Marlin 3D Printer Firmware + * + * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * 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 3 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, see . + * + */ + +#include "../inc/MarlinConfig.h" + +#if ENABLED(IIC_BL24CXX_EEPROM) + +/** + * PersistentStore for Arduino-style EEPROM interface + * with simple implementations supplied by Marlin. + */ + +#include "BL24CXX.h" +#include + +#ifndef EEPROM_WRITE_DELAY + #define EEPROM_WRITE_DELAY 10 +#endif +#ifndef EEPROM_DEVICE_ADDRESS + #define EEPROM_DEVICE_ADDRESS (0x50 << 1) +#endif + +// IO direction setting +#define SDA_IN() do{ PIN_MAP[IIC_EEPROM_SDA].gpio_device->regs->CRH &= 0XFFFF0FFF; PIN_MAP[IIC_EEPROM_SDA].gpio_device->regs->CRH |= 8 << 12; }while(0) +#define SDA_OUT() do{ PIN_MAP[IIC_EEPROM_SDA].gpio_device->regs->CRH &= 0XFFFF0FFF; PIN_MAP[IIC_EEPROM_SDA].gpio_device->regs->CRH |= 3 << 12; }while(0) + +// IO ops +#define IIC_SCL_0() WRITE(IIC_EEPROM_SCL, LOW) +#define IIC_SCL_1() WRITE(IIC_EEPROM_SCL, HIGH) +#define IIC_SDA_0() WRITE(IIC_EEPROM_SDA, LOW) +#define IIC_SDA_1() WRITE(IIC_EEPROM_SDA, HIGH) +#define READ_SDA() READ(IIC_EEPROM_SDA) + +// +// Simple IIC interface via libmaple +// + +// Initialize IIC +void IIC::init() { + SET_OUTPUT(IIC_EEPROM_SDA); + SET_OUTPUT(IIC_EEPROM_SCL); + IIC_SCL_1(); + IIC_SDA_1(); +} + +// Generate IIC start signal +void IIC::start() { + SDA_OUT(); // SDA line output + IIC_SDA_1(); + IIC_SCL_1(); + delay_us(4); + IIC_SDA_0(); // START:when CLK is high, DATA change from high to low + delay_us(4); + IIC_SCL_0(); // Clamp the I2C bus, ready to send or receive data +} + +// Generate IIC stop signal +void IIC::stop() { + SDA_OUT(); // SDA line output + IIC_SCL_0(); + IIC_SDA_0(); // STOP:when CLK is high DATA change from low to high + delay_us(4); + IIC_SCL_1(); + IIC_SDA_1(); // Send I2C bus end signal + delay_us(4); +} + +// Wait for the response signal to arrive +// 1 = failed to receive response +// 0 = response received +uint8_t IIC::wait_ack() { + uint8_t ucErrTime = 0; + SDA_IN(); // SDA is set as input + IIC_SDA_1(); delay_us(1); + IIC_SCL_1(); delay_us(1); + while (READ_SDA()) { + if (++ucErrTime > 250) { + stop(); + return 1; + } + } + IIC_SCL_0(); // Clock output 0 + return 0; +} + +// Generate ACK response +void IIC::ack() { + IIC_SCL_0(); + SDA_OUT(); + IIC_SDA_0(); + delay_us(2); + IIC_SCL_1(); + delay_us(2); + IIC_SCL_0(); +} + +// No ACK response +void IIC::nAck() { + IIC_SCL_0(); + SDA_OUT(); + IIC_SDA_1(); + delay_us(2); + IIC_SCL_1(); + delay_us(2); + IIC_SCL_0(); +} + +// Send one IIC byte +// Return whether the slave responds +// 1 = there is a response +// 0 = no response +void IIC::send_byte(uint8_t txd) { + SDA_OUT(); + IIC_SCL_0(); // Pull down the clock to start data transmission + LOOP_L_N(t, 8) { + // IIC_SDA = (txd & 0x80) >> 7; + if (txd & 0x80) IIC_SDA_1(); else IIC_SDA_0(); + txd <<= 1; + delay_us(2); // All three delays are necessary for TEA5767 + IIC_SCL_1(); + delay_us(2); + IIC_SCL_0(); + delay_us(2); + } +} + +// Read 1 byte, when ack=1, send ACK, ack=0, send nACK +uint8_t IIC::read_byte(unsigned char ack_chr) { + unsigned char receive = 0; + SDA_IN(); // SDA is set as input + LOOP_L_N(i, 8) { + IIC_SCL_0(); + delay_us(2); + IIC_SCL_1(); + receive <<= 1; + if (READ_SDA()) receive++; + delay_us(1); + } + ack_chr ? ack() : nAck(); // Send ACK / send nACK + return receive; +} + +/******************** EEPROM ********************/ + +// Initialize the IIC interface +void BL24CXX::init() { IIC::init(); } + +// Read a byte at the specified address +// ReadAddr: the address to start reading +// Return: the byte read +uint8_t BL24CXX::readOneByte(uint16_t ReadAddr) { + uint8_t temp = 0; + IIC::start(); + if (EE_TYPE > BL24C16) { + IIC::send_byte(EEPROM_DEVICE_ADDRESS); // Send write command + IIC::wait_ack(); + IIC::send_byte(ReadAddr >> 8); // Send high address + IIC::wait_ack(); + } + else + IIC::send_byte(EEPROM_DEVICE_ADDRESS + ((ReadAddr >> 8) << 1)); // Send device address 0xA0, write data + + IIC::wait_ack(); + IIC::send_byte(ReadAddr & 0xFF); // Send low address + IIC::wait_ack(); + IIC::start(); + IIC::send_byte(EEPROM_DEVICE_ADDRESS | 0x01); // Send byte + IIC::wait_ack(); + temp = IIC::read_byte(0); + IIC::stop(); // Generate a stop condition + return temp; +} + +// Write a data at the address specified by BL24CXX +// WriteAddr: The destination address for writing data +// DataToWrite: the data to be written +void BL24CXX::writeOneByte(uint16_t WriteAddr, uint8_t DataToWrite) { + IIC::start(); + if (EE_TYPE > BL24C16) { + IIC::send_byte(EEPROM_DEVICE_ADDRESS); // Send write command + IIC::wait_ack(); + IIC::send_byte(WriteAddr >> 8); // Send high address + } + else + IIC::send_byte(EEPROM_DEVICE_ADDRESS + ((WriteAddr >> 8) << 1)); // Send device address 0xA0, write data + + IIC::wait_ack(); + IIC::send_byte(WriteAddr & 0xFF); // Send low address + IIC::wait_ack(); + IIC::send_byte(DataToWrite); // Receiving mode + IIC::wait_ack(); + IIC::stop(); // Generate a stop condition + delay(10); +} + +// Start writing data of length Len at the specified address in BL24CXX +// This function is used to write 16bit or 32bit data. +// WriteAddr: the address to start writing +// DataToWrite: the first address of the data array +// Len: The length of the data to be written 2, 4 +void BL24CXX::writeLenByte(uint16_t WriteAddr, uint32_t DataToWrite, uint8_t Len) { + LOOP_L_N(t, Len) + writeOneByte(WriteAddr + t, (DataToWrite >> (8 * t)) & 0xFF); +} + +// Start reading data of length Len from the specified address in BL24CXX +// This function is used to read 16bit or 32bit data. +// ReadAddr: the address to start reading +// Return value: data +// Len: The length of the data to be read 2,4 +uint32_t BL24CXX::readLenByte(uint16_t ReadAddr, uint8_t Len) { + uint32_t temp = 0; + LOOP_L_N(t, Len) { + temp <<= 8; + temp += readOneByte(ReadAddr + Len - t - 1); + } + return temp; +} + +// Check if BL24CXX is normal +// Return 1: Detection failed +// return 0: detection is successful +#define BL24CXX_TEST_ADDRESS 0x00 +#define BL24CXX_TEST_VALUE 0x55 + +bool BL24CXX::_check() { + return (readOneByte(BL24CXX_TEST_ADDRESS) != BL24CXX_TEST_VALUE); // false = success! +} + +bool BL24CXX::check() { + if (_check()) { // Value was written? Good EEPROM! + writeOneByte(BL24CXX_TEST_ADDRESS, BL24CXX_TEST_VALUE); // Write now and check. + return _check(); + } + return false; // success! +} + +// Start reading the specified number of data at the specified address in BL24CXX +// ReadAddr: The address to start reading is 0~255 for 24c02 +// pBuffer: the first address of the data array +// NumToRead: the number of data to be read +void BL24CXX::read(uint16_t ReadAddr, uint8_t *pBuffer, uint16_t NumToRead) { + for (; NumToRead; NumToRead--) + *pBuffer++ = readOneByte(ReadAddr++); +} + +// Start writing the specified number of data at the specified address in BL24CXX +// WriteAddr: the address to start writing, 0~255 for 24c02 +// pBuffer: the first address of the data array +// NumToWrite: the number of data to be written +void BL24CXX::write(uint16_t WriteAddr, uint8_t *pBuffer, uint16_t NumToWrite) { + for (; NumToWrite; NumToWrite--, WriteAddr++) + writeOneByte(WriteAddr, *pBuffer++); +} + +#endif // IIC_BL24CXX_EEPROM diff --git a/Marlin/src/lcd/dwin/eeprom_BL24CXX.h b/Marlin/src/libs/BL24CXX.h similarity index 65% rename from Marlin/src/lcd/dwin/eeprom_BL24CXX.h rename to Marlin/src/libs/BL24CXX.h index e253cc9be2..b069c196c0 100644 --- a/Marlin/src/lcd/dwin/eeprom_BL24CXX.h +++ b/Marlin/src/libs/BL24CXX.h @@ -22,25 +22,12 @@ #pragma once /******************************************************************************** - * @file eeprom_BL24CXX.h + * @file BL24CXX.h * @brief i2c EEPROM for Ender 3 v2 board (4.2.2) ********************************************************************************/ -#include - /******************** IIC ********************/ -//IO direction setting -#define SDA_IN() do{ PIN_MAP[IIC_EEPROM_SDA].gpio_device->regs->CRH &= 0XFFFF0FFF; PIN_MAP[IIC_EEPROM_SDA].gpio_device->regs->CRH |= 8 << 12; }while(0) -#define SDA_OUT() do{ PIN_MAP[IIC_EEPROM_SDA].gpio_device->regs->CRH &= 0XFFFF0FFF; PIN_MAP[IIC_EEPROM_SDA].gpio_device->regs->CRH |= 3 << 12; }while(0) - -//IO operation function -#define IIC_SCL_0() WRITE(IIC_EEPROM_SCL, LOW) -#define IIC_SCL_1() WRITE(IIC_EEPROM_SCL, HIGH) -#define IIC_SDA_0() WRITE(IIC_EEPROM_SDA, LOW) -#define IIC_SDA_1() WRITE(IIC_EEPROM_SDA, HIGH) -#define READ_SDA() READ(IIC_EEPROM_SDA) - class BL24CXX; // All operation functions of IIC @@ -55,9 +42,6 @@ protected: static uint8_t wait_ack(); // IIC waits for ACK signal static void ack(); // IIC sends ACK signal static void nAck(); // IIC does not send ACK signal - - static void write_one_byte(uint8_t daddr, uint8_t addr, uint8_t data); - static uint8_t read_one_byte(uint8_t daddr, uint8_t addr); }; /******************** EEPROM ********************/ @@ -74,13 +58,15 @@ protected: #define EE_TYPE BL24C16 class BL24CXX { +private: + static bool _check(); // Check the device public: - static void init(); // Initialize IIC - static uint8_t check(); // Check the device - static uint8_t readOneByte(uint16_t ReadAddr); // Read a byte at the specified address - static void writeOneByte(uint16_t WriteAddr, uint8_t DataToWrite); // Write a byte at the specified address - static void writeLenByte(uint16_t WriteAddr, uint32_t DataToWrite, uint8_t Len);// The specified address begins to write the data of the specified length - static uint32_t readLenByte(uint16_t ReadAddr, uint8_t Len); // The specified address starts to read the data of the specified length - static void write(uint16_t WriteAddr, uint8_t *pBuffer, uint16_t NumToWrite); // Write the specified length of data from the specified address - static void read(uint16_t ReadAddr, uint8_t *pBuffer, uint16_t NumToRead); // Read the data of the specified length from the specified address + static void init(); // Initialize IIC + static bool check(); // Check / recheck the device + static uint8_t readOneByte(uint16_t ReadAddr); // Read a byte at the specified address + static void writeOneByte(uint16_t WriteAddr, uint8_t DataToWrite); // Write a byte at the specified address + static void writeLenByte(uint16_t WriteAddr, uint32_t DataToWrite, uint8_t Len); // The specified address begins to write the data of the specified length + static uint32_t readLenByte(uint16_t ReadAddr, uint8_t Len); // The specified address starts to read the data of the specified length + static void write(uint16_t WriteAddr, uint8_t *pBuffer, uint16_t NumToWrite); // Write the specified length of data from the specified address + static void read(uint16_t ReadAddr, uint8_t *pBuffer, uint16_t NumToRead); // Read the data of the specified length from the specified address }; diff --git a/Marlin/src/libs/hex_print_routines.cpp b/Marlin/src/libs/hex_print_routines.cpp index 3ab81e596a..5909ffd7d0 100644 --- a/Marlin/src/libs/hex_print_routines.cpp +++ b/Marlin/src/libs/hex_print_routines.cpp @@ -23,7 +23,7 @@ #include "../inc/MarlinConfig.h" #include "../gcode/parser.h" -#if ANY(AUTO_BED_LEVELING_UBL, M100_FREE_MEMORY_WATCHER, DEBUG_GCODE_PARSER, TMC_DEBUG) +#if ANY(AUTO_BED_LEVELING_UBL, M100_FREE_MEMORY_WATCHER, DEBUG_GCODE_PARSER, TMC_DEBUG, MARLIN_DEV_MODE) #include "hex_print_routines.h" diff --git a/Marlin/src/pins/stm32f1/pins_CREALITY_V4.h b/Marlin/src/pins/stm32f1/pins_CREALITY_V4.h index cf7594f784..8a413945b7 100644 --- a/Marlin/src/pins/stm32f1/pins_CREALITY_V4.h +++ b/Marlin/src/pins/stm32f1/pins_CREALITY_V4.h @@ -47,12 +47,12 @@ #if ENABLED(IIC_BL24CXX_EEPROM) #define IIC_EEPROM_SDA PA11 #define IIC_EEPROM_SCL PA12 - //#define MARLIN_EEPROM_SIZE 0x4000 // 16Kb (24c16) + #define MARLIN_EEPROM_SIZE 0x800 // 2Kb (24C16) + #else + #define SDCARD_EEPROM_EMULATION // SD EEPROM until all EEPROM is BL24CXX + #define MARLIN_EEPROM_SIZE 0x800 // 2Kb #endif - #define SDCARD_EEPROM_EMULATION // SD EEPROM until all EEPROM is BL24CXX - #define MARLIN_EEPROM_SIZE 0x1000 // 4Kb - // SPI //#define SPI_EEPROM // EEPROM on SPI-0 //#define SPI_CHAN_EEPROM1 ? diff --git a/buildroot/tests/STM32F103RET6_creality-tests b/buildroot/tests/STM32F103RET6_creality-tests index f9ae634ebc..ca723c7aa2 100644 --- a/buildroot/tests/STM32F103RET6_creality-tests +++ b/buildroot/tests/STM32F103RET6_creality-tests @@ -10,6 +10,7 @@ set -e # Build with configs included in the PR # use_example_configs "Creality/Ender-3 V2" +opt_enable MARLIN_DEV_MODE exec_test $1 $2 "Ender 3 v2" restore_configs