Browse Source

Возможность использовать SPI флеш для EEPROM

Поддержка sd карт SDv2
Загрузка прошивки по WIFI
pull/1/head
Sergey 4 years ago
parent
commit
db29115cf3
  1. 40
      Marlin/Configuration.h
  2. 10
      Marlin/src/HAL/STM32F1/HAL.h
  3. 12
      Marlin/src/HAL/STM32F1/eeprom.cpp
  4. 198
      Marlin/src/HAL/STM32F1/eeprom_i2c_at24.cpp
  5. 272
      Marlin/src/HAL/STM32F1/eeprom_spi_w25q.cpp
  6. 20
      Marlin/src/feature/touch/xpt2046.cpp
  7. 3
      Marlin/src/feature/touch/xpt2046.h
  8. 4
      Marlin/src/libs/fatfs/ff.cpp
  9. 20
      Marlin/src/libs/fatfs/sdio_driver.cpp
  10. 13
      Marlin/src/libs/fatfs/sdio_driver.h
  11. 7
      Marlin/src/module/mks_wifi/mks_wifi.cpp
  12. 2
      Marlin/src/module/mks_wifi/mks_wifi.h
  13. 14
      Marlin/src/module/mks_wifi/mks_wifi_sd.cpp
  14. 129
      Marlin/src/module/mks_wifi/small_cmsis.h
  15. 1
      Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO.h
  16. 158
      README.md
  17. 6
      buildroot/share/PlatformIO/scripts/mks_robin_nano.py
  18. BIN
      firmware/2208/Robin_nano35.bin
  19. BIN
      firmware/bootloader/fb_4s_bootloader.bin
  20. BIN
      firmware/std/Robin_nano35.bin
  21. 4
      platformio.ini

40
Marlin/Configuration.h

@ -1459,14 +1459,48 @@
//#define DISABLE_M503 // Saves ~2700 bytes of PROGMEM. Disable for release!
#define EEPROM_CHITCHAT // Give feedback on EEPROM commands. Disable to save PROGMEM.
//#define EEPROM_BOOT_SILENT // Keep M503 quiet and only give errors during first load
#if ENABLED(EEPROM_SETTINGS)
/*
MKS Robin EEPROM:
EEPROM_SD
EEPROM_AT24C16
EEPROM_W25Q
*/
#define EEPROM_SD
#if ENABLED(EEPROM_AT24C16)
#undef SDCARD_EEPROM_EMULATION
#undef USE_REAL_EEPROM
#undef FLASH_EEPROM_EMULATION
#undef SRAM_EEPROM_EMULATION
#define I2C_EEPROM_AT24C16
#define USE_WIRED_EEPROM 1
#define E2END (2*1024 - 1)
#endif
#if ENABLED(EEPROM_W25Q)
#undef SDCARD_EEPROM_EMULATION
#undef USE_REAL_EEPROM
#undef FLASH_EEPROM_EMULATION
#undef SRAM_EEPROM_EMULATION
#undef I2C_EEPROM_AT24C16
#define SPI_EEPROM_W25Q
#define SPI_EEPROM_OFFSET 0x700000
#define USE_WIRED_EEPROM 1
#define E2END (2*1024 - 1)
#endif
#if ENABLED(EEPROM_SD)
#define SDCARD_EEPROM_EMULATION
#undef USE_REAL_EEPROM
#undef FLASH_EEPROM_EMULATION
#undef SRAM_EEPROM_EMULATION
//#define USE_WIRED_EEPROM 1
//#define I2C_EEPROM_AT24C16
//#define E2END (2*1024 - 1)
#undef I2C_EEPROM_AT24C16
#undef SPI_EEPROM_W25Q
#undef USE_WIRED_EEPROM
#endif
#define EEPROM_AUTO_INIT // Init EEPROM automatically on any errors.
#endif

10
Marlin/src/HAL/STM32F1/HAL.h

@ -257,16 +257,16 @@ static int freeMemory() {
* Wire library should work for i2c EEPROMs.
*/
#if ENABLED(I2C_EEPROM_AT24C16)
uint8_t eeprom_read_byte(uint16_t *pos);
void eeprom_write_byte(uint16_t *pos, unsigned char value);
#if ANY(I2C_EEPROM_AT24C16, SPI_EEPROM_W25Q)
void eeprom_hw_init(void);
#else
void eeprom_hw_deinit(void);
#endif
uint8_t eeprom_read_byte(uint8_t *pos);
void eeprom_write_byte(uint8_t *pos, unsigned char value);
void eeprom_read_block(void *__dst, const void *__src, size_t __n);
void eeprom_update_block(const void *__src, void *__dst, size_t __n);
#endif
//

12
Marlin/src/HAL/STM32F1/eeprom.cpp

@ -27,6 +27,7 @@
#include "../shared/eeprom_api.h"
bool PersistentStore::access_start() {
DEBUG("EEPROM start");
#if ENABLED(SPI_EEPROM)
#if SPI_CHAN_EEPROM1 == 1
SET_OUTPUT(BOARD_SPI1_SCK_PIN);
@ -36,13 +37,20 @@ bool PersistentStore::access_start() {
#endif
spiInit(0);
#endif
#if ENABLED(I2C_EEPROM_AT24C16)
#if ANY(I2C_EEPROM_AT24C16, SPI_EEPROM_W25Q)
eeprom_hw_init();
#endif
return true;
}
bool PersistentStore::access_finish() { return true; }
bool PersistentStore::access_finish() {
#if ANY(I2C_EEPROM_AT24C16, SPI_EEPROM_W25Q)
eeprom_hw_deinit();
#endif
return true;
}
bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) {
while (size--) {

198
Marlin/src/HAL/STM32F1/eeprom_i2c_at24.cpp

@ -0,0 +1,198 @@
/**
AT24C16, 16K SERIAL EEPROM:
Internally organized with 128 pages of 16 bytes each (2048 bytes)
16K requires an 11-bit data word address for random word addressing.
The 16K does not use any device address bits but instead the 3 bits are used for mem-
ory page addressing. These page addressing bits on the 4K, 8K and 16K devices
should be considered the most significant bits of the data word address which follows.
The A0, A1 and A2 pins are no connect.
*/
#include "../../inc/MarlinConfig.h"
#if ENABLED(I2C_EEPROM_AT24C16)
#include "../HAL.h"
#include "../../module/mks_wifi/small_cmsis.h"
#include "../../module/mks_wifi/dwt.h"
#define DEV_ADDR 0xA0
#define FSMC_DISABLE RCC->AHBENR &= ~RCC_AHBENR_FSMCEN //Конфликт на ноге FSMC_NADV с I2C. На время передачи приходится отключать FSMC
#define FSMC_RESTORE RCC->AHBENR |= RCC_AHBENR_FSMCEN;
#define I2C_TIMEOUT 2000 //таймаут на ожидание опереций I2C.
#define CHECK_TIMEOUT do{if(dwt_get_timeout() == 0){ERROR("Timeout");return 0;}}while(0)
static bool waitSRBitSet(uint32_t Bit);
static uint8_t i2c_write(const uint8_t hw_adr, uint8_t *data, uint32_t len);
static uint8_t i2c_read(const uint8_t hw_adr, uint16_t addr, uint8_t *data, uint32_t len);
void eeprom_hw_deinit(void){
DEBUG("Finish I2C");
}
void eeprom_hw_init(void){
/*
PB6 SCL Alternate function open drain
PB7 SDA Alternate function open drain
*/
DEBUG("Init I2C");
dwt_init();
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN|RCC_APB2ENR_AFIOEN;
PORTB->CRL |= (GPIO_CRL_MODE6|GPIO_CRL_MODE7|GPIO_CRL_CNF6|GPIO_CRL_CNF7);
AFIO->MAPR2 |= AFIO_MAPR2_FSMC_NADV_REMAP; //Remap по факту не работает, бит не устанавливается.
RCC->APB1ENR|= RCC_APB1ENR_I2C1EN;
I2C1->CR1 = I2C_CR1_SWRST;
I2C1->CR1 = 0;
//Тактовая 72Mhz, PCLK 36Mhz
I2C1->CCR = (180 << I2C_CCR_CCR_Pos);
I2C1->CR2 = (36 << I2C_CR2_FREQ_Pos);
I2C1->TRISE = 37;
I2C1->CR1 = I2C_CR1_PE;
}
void eeprom_write_byte(uint8_t *pos, unsigned char value){
uint8_t data[2];
FSMC_DISABLE;
data[0]=(uint8_t)((unsigned)pos % 256);
data[1]=(uint8_t)(value);
if(!i2c_write((DEV_ADDR+(uint8_t)(((unsigned)pos/256)<<1)),data,2)){
ERROR("write failed");
}
safe_delay(20); //Задержка на время пока eeprom пишет.
FSMC_RESTORE;
}
uint8_t eeprom_read_byte(uint8_t *pos) {
uint8_t data;
FSMC_DISABLE;
if(!i2c_read(DEV_ADDR, (uint16_t)((unsigned)pos), &data, 1)){
ERROR("read failed");
data=0;
}
safe_delay(1); //небольшая пауза перед включением FSMC, чтобы состояние STOP успело выставиться на линии.
FSMC_RESTORE;
return data;
}
void eeprom_read_block(void *__dst, const void *__src, size_t __n){
ERROR("Call to missing function");
};
void eeprom_update_block(const void *__src, void *__dst, size_t __n){
ERROR("Call to missing function");
};
static uint8_t i2c_write(const uint8_t hw_adr, uint8_t *data, uint32_t len){
DEBUG("i2c write at %d val %0X",data[0],data[1]);
dwt_settimeout(I2C_TIMEOUT);
DEBUG("Wait busy");
while(I2C1->SR2 & I2C_SR2_BUSY) {CHECK_TIMEOUT;};
I2C1->CR1 = I2C_CR1_PE | I2C_CR1_START;
dwt_settimeout(I2C_TIMEOUT);
DEBUG("Wait SB");
while(!(I2C1->SR1 & I2C_SR1_SB)) {CHECK_TIMEOUT;};
I2C1->DR = (hw_adr & 0xFE);
if(!waitSRBitSet(I2C_SR1_ADDR)) return false;
(void)I2C1->SR2;
while(len--){
if(!waitSRBitSet(I2C_SR1_TXE)) return false;
I2C1->DR = *data++;
}
dwt_settimeout(I2C_TIMEOUT);
DEBUG("Wait BTF");
while(!((I2C1->SR1 & I2C_SR1_TXE) && (I2C1->SR1 & I2C_SR1_BTF))) {CHECK_TIMEOUT;};
I2C1->CR1 = I2C_CR1_PE | I2C_CR1_STOP;
return 1;
}
static uint8_t i2c_read(const uint8_t hw_adr, uint16_t addr, uint8_t *data, uint32_t len){
dwt_settimeout(I2C_TIMEOUT);
DEBUG("Wait busy");
while(I2C1->SR2 & I2C_SR2_BUSY) {CHECK_TIMEOUT;};
//Запись адреса
I2C1->CR1 = I2C_CR1_PE | I2C_CR1_START;
dwt_settimeout(I2C_TIMEOUT);
DEBUG("Wait SB");
while(!(I2C1->SR1 & I2C_SR1_SB)) {CHECK_TIMEOUT;}; //Условие старт
I2C1->DR = ((hw_adr & 0xFE) + ((addr/256) << 1));
if(!waitSRBitSet(I2C_SR1_ADDR)) return false; //i2c адрес отправлен
I2C1->SR2;
if(!waitSRBitSet(I2C_SR1_TXE)) return false;
I2C1->DR = addr%256; //адрес в памяти отправлен
dwt_settimeout(I2C_TIMEOUT);
DEBUG("Wait BTF");
while(!((I2C1->SR1 & I2C_SR1_TXE) && (I2C1->SR1 & I2C_SR1_BTF))) {CHECK_TIMEOUT;};
//Чтение
I2C1->CR1 = I2C_CR1_PE | I2C_CR1_START | I2C_CR1_ACK;
dwt_settimeout(I2C_TIMEOUT);
DEBUG("Wait SB");
while(!(I2C1->SR1 & I2C_SR1_SB)) {CHECK_TIMEOUT;};
I2C1->DR = hw_adr|1;
if(!waitSRBitSet(I2C_SR1_ADDR)) return false;
I2C1->SR2;
I2C1->CR1 = I2C_CR1_PE | I2C_CR1_STOP;
if(!waitSRBitSet(I2C_SR1_RXNE)) return false;
*data = I2C1->DR;
return true;
}
static bool waitSRBitSet(uint32_t Bit){
uint32_t sr;
dwt_settimeout(I2C_TIMEOUT);
do{
sr = I2C1->SR1;
if(sr & ( I2C_SR1_AF | I2C_SR1_ARLO | I2C_SR1_BERR)){
I2C1->CR1 = I2C_CR1_PE | I2C_CR1_STOP;
I2C1->SR1 = 0;
ERROR("I2C Error flag %0X",sr);
return false;
}
if(dwt_get_timeout() == 0){
ERROR("Timeout %0X",Bit);
return false;
}
}while(!(sr & Bit));
return true;
};
#endif // I2C_EEPROM

272
Marlin/src/HAL/STM32F1/eeprom_spi_w25q.cpp

@ -0,0 +1,272 @@
/**
MKS Robin Nano
U5 W25Q64BV, 16K SERIAL EEPROM:
*/
#include "../../inc/MarlinConfig.h"
#if ENABLED(SPI_EEPROM_W25Q)
#include "../HAL.h"
#include "../../module/mks_wifi/small_cmsis.h"
#include "../../module/mks_wifi/dwt.h"
#define SPI_DIR_READ 0
#define SPI_DIR_WRITE 1
#define W25X_WriteEnable 0x06
#define W25X_WriteDisable 0x04
#define W25X_ReadStatusReg 0x05
#define W25X_WriteStatusReg 0x01
#define W25X_ReadData 0x03
#define W25X_FastReadData 0x0B
#define W25X_PageProgram 0x02
#define W25X_BlockErase 0xD8
#define W25X_SectorErase 0x20
#define W25X_ChipErase 0xC7
#define W25X_ReleasePowerDown 0xAB
#define W25X_DeviceID 0xAB
#define W25X_ManufactDeviceID 0x90
#define W25X_JedecDeviceID 0x9F
#define SPI_EEPROM_SIZE 2048
#define SPIFLASH_PAGESIZE 256
#define SPI_TIMEOUT 2000 //таймаут на ожидание опереций
#define CHECK_TIMEOUT do{if(dwt_get_timeout() == 0){ERROR("Timeout");return 0;}}while(0)
#define SPI2_START PORTB->BSRR=GPIO_BSRR_BR12
#define SPI2_STOP PORTB->BSRR=GPIO_BSRR_BS12
volatile uint8_t spi_eeprom[SPI_EEPROM_SIZE];
uint8_t spi_send(uint8_t data);
void spi_read(uint32_t addr, uint8_t *buf, uint32_t len);
void spi_write(uint32_t addr, uint8_t *buf, uint32_t len);
uint8_t spi_read_status(void);
void eeprom_hw_init(void){
uint32_t tmp;
uint8_t device_id, manuf_id;
uint16_t chip_id;
/*
SPI2
MISO - PB14 Input floating / Input pull-up
MOSI - PB15 Alternate function push-pull
SCK - PB13 Alternate function push-pull
CS - PB12 Out push-pull
*/
DEBUG("Start SPI");
dwt_init();
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN|RCC_APB2ENR_AFIOEN;
tmp = PORTB->CRH;
tmp |= (GPIO_CRH_MODE13|GPIO_CRH_MODE15|GPIO_CRH_CNF13|GPIO_CRH_CNF15);
tmp &= ~(GPIO_CRH_MODE14|GPIO_CRH_CNF14);
tmp |= GPIO_CRH_CNF14_0;
tmp &= ~GPIO_CRH_CNF12;
tmp |= GPIO_CRH_MODE12;
PORTB->CRH = tmp;
SPI2_STOP;
RCC->APB1ENR|= RCC_APB1ENR_SPI2EN;
SPI2->CR1 = SPI_CR1_SSM|\
SPI_CR1_SSI|\
(6 << SPI_CR1_BR_Pos)|\
SPI_CR1_CPHA|\
SPI_CR1_MSTR;
SPI2->CR1 |= SPI_CR1_SPE;
//Wake up
SPI2_START;
spi_send(W25X_ReleasePowerDown);
SPI2_STOP;
for(uint32_t i=0; i<0x1000; i++){NOP;} //3us для выхода из power down
//Device ID
SPI2_START;
spi_send(W25X_DeviceID);
for(uint32_t i=0; i<3; i++){spi_send(0);}
device_id = spi_send(0);
SPI2_STOP;
//Jedec ID
SPI2_START;
spi_send(W25X_JedecDeviceID);
manuf_id = spi_send(0);
chip_id = spi_send(0) << 8;
chip_id |= spi_send(0);
DEBUG("W25Q Device ID %0X Manuf ID: %0X Chip ID %0X",device_id,manuf_id,chip_id);
SPI2_STOP;
spi_read(SPI_EEPROM_OFFSET,(uint8_t *)spi_eeprom,SPI_EEPROM_SIZE);
}
void eeprom_hw_deinit(void){
DEBUG("Finish SPI");
//Write Enable
SPI2_START;
spi_send(W25X_WriteEnable);
SPI2_STOP;
while (spi_read_status() & 1){ //Busy
NOP;
}
//Erase 4K
SPI2_START;
spi_send(W25X_SectorErase);
spi_send((SPI_EEPROM_OFFSET >> 16) & 0xFF);
spi_send((SPI_EEPROM_OFFSET >> 8) & 0xFF);
spi_send(SPI_EEPROM_OFFSET & 0xFF);
SPI2_STOP;
while (spi_read_status() & 1){ //Busy
NOP;
}
//write
spi_write(SPI_EEPROM_OFFSET,(uint8_t *)spi_eeprom,SPI_EEPROM_SIZE);
//deinit spi
}
void eeprom_write_byte(uint8_t *pos, unsigned char value){
uint16_t addr=(unsigned)pos;
if(addr < SPI_EEPROM_SIZE){
spi_eeprom[addr]=value;
}else{
ERROR("Write out of SPI size: %d %d",addr,SPI_EEPROM_SIZE);
}
}
uint8_t eeprom_read_byte(uint8_t *pos) {
uint16_t addr=(unsigned)pos;
if(addr < SPI_EEPROM_SIZE){
return spi_eeprom[addr];
}else{
ERROR("Read out of SPI size: %d %d",addr,SPI_EEPROM_SIZE);
return 0;
}
}
void eeprom_read_block(void *__dst, const void *__src, size_t __n){
ERROR("Call to missing function");
};
void eeprom_update_block(const void *__src, void *__dst, size_t __n){
ERROR("Call to missing function");
};
uint8_t spi_send(uint8_t data){
while((SPI2->SR & SPI_SR_TXE) == 0){NOP;};
SPI2->DR = data;
while((SPI2->SR & SPI_SR_RXNE) == 0){NOP;};
return SPI2->DR;
}
void spi_read(uint32_t addr, uint8_t *buf, uint32_t len){
if( (len == 0) || (len > SPI_EEPROM_SIZE) ){
ERROR("Len size error: %d",len);
return;
}
addr &= 0xFFFFFF; //24bit address
SPI2_START;
if(len == 1){
spi_send(W25X_ReadData);
spi_send((addr >> 16) & 0xFF);
spi_send((addr >> 8) & 0xFF);
spi_send(addr & 0xFF);
}else{
spi_send(W25X_FastReadData);
spi_send((addr >> 16) & 0xFF);
spi_send((addr >> 8) & 0xFF);
spi_send(addr & 0xFF);
spi_send(0);
}
while (len--){
*buf++ = spi_send(0);
}
SPI2_STOP;
}
void spi_write(uint32_t addr, uint8_t *buf, uint32_t len){
uint16_t bytes_in_page = SPIFLASH_PAGESIZE - (addr % SPIFLASH_PAGESIZE);
uint16_t offset = 0;
addr &= 0xFFFFFF; //24bit address
while (spi_read_status() & 1){ //Busy
NOP;
}
//Write Enable
while (len > 0){
uint16_t batch_size = (len <= bytes_in_page) ? len : bytes_in_page;
SPI2_START;
spi_send(W25X_WriteEnable);
SPI2_STOP;
while (spi_read_status() & 1){ //Busy
NOP;
}
SPI2_START;
spi_send(W25X_PageProgram);
spi_send((addr >> 16) & 0xFF);
spi_send((addr >> 8) & 0xFF);
spi_send(addr & 0xFF);
for (uint32_t i = 0; i < batch_size; i++){
spi_send(((uint8_t*)buf)[offset + i]);
}
SPI2_STOP;
//wait till it's programmed
while (spi_read_status() & 2){ //Busy
NOP;
}
addr += batch_size;
offset += batch_size;
len -= batch_size;
bytes_in_page = SPIFLASH_PAGESIZE;
}
}
uint8_t spi_read_status(void){
uint8_t data;
SPI2_START;
spi_send(W25X_ReadStatusReg);
data = spi_send(0);
SPI2_STOP;
return data;
}
#endif // SPI_EEPROM_W25Q

20
Marlin/src/feature/touch/xpt2046.cpp

@ -43,18 +43,21 @@
XPT2046 touch;
extern int8_t encoderDiff;
void XPT2046::init() {
void XPT2046::begin() {
SET_INPUT(TOUCH_MISO_PIN);
SET_OUTPUT(TOUCH_MOSI_PIN);
SET_OUTPUT(TOUCH_SCK_PIN);
OUT_WRITE(TOUCH_CS_PIN, HIGH);
}
#if PIN_EXISTS(TOUCH_INT)
// Optional Pendrive interrupt pin
SET_INPUT(TOUCH_INT_PIN);
#endif
void XPT2046::end() {
SET_INPUT(TOUCH_MISO_PIN);
SET_INPUT(TOUCH_MOSI_PIN);
SET_INPUT(TOUCH_SCK_PIN);
}
// Read once to enable pendrive status pin
void XPT2046::init() {
getInTouch(XPT2046_X);
}
@ -78,7 +81,8 @@ uint8_t XPT2046::read_buttons() {
y = uint16_t(((uint32_t(getInTouch(XPT2046_Y))) * tsoffsets[2]) >> 16) + tsoffsets[3];
if (!isTouched()) return 0; // Fingers must still be on the TS for a valid read.
if (y < 175 || y > 234) return 0;
//@ little more Y
if (y < 165 || y > 234) return 0;
return WITHIN(x, 14, 77) ? EN_D
: WITHIN(x, 90, 153) ? EN_A
@ -100,6 +104,7 @@ bool XPT2046::isTouched() {
uint16_t XPT2046::getInTouch(const XPTCoordinate coordinate) {
uint16_t data[3];
begin();
OUT_WRITE(TOUCH_CS_PIN, LOW);
const uint8_t coord = uint8_t(coordinate) | XPT2046_CONTROL | XPT2046_DFR_MODE;
@ -121,6 +126,7 @@ uint16_t XPT2046::getInTouch(const XPTCoordinate coordinate) {
}
WRITE(TOUCH_CS_PIN, HIGH);
end();
uint16_t delta01 = _MAX(data[0], data[1]) - _MIN(data[0], data[1]),
delta02 = _MAX(data[0], data[2]) - _MIN(data[0], data[2]),

3
Marlin/src/feature/touch/xpt2046.h

@ -41,6 +41,9 @@ enum XPTCoordinate : uint8_t {
class XPT2046 {
public:
static void init();
static void begin();
static void end();
static uint8_t read_buttons();
bool getTouchPoint(uint16_t &x, uint16_t &y);
static bool isTouched();

4
Marlin/src/libs/fatfs/ff.cpp

@ -6534,7 +6534,7 @@ static void putc_bfd (putbuff* pb, TCHAR c)
WCHAR hs, wc;
#if FF_LFN_UNICODE == 2
DWORD dc;
TCHAR *tp;
const TCHAR *tp;
#endif
#endif
@ -6576,7 +6576,7 @@ static void putc_bfd (putbuff* pb, TCHAR c)
return;
}
}
tp = (TCHAR*)pb->bs;
tp = (const TCHAR*)pb->bs;
dc = tchar2uni(&tp); /* UTF-8 ==> UTF-16 */
if (dc == 0xFFFFFFFF) return; /* Wrong code? */
wc = (WCHAR)dc;

20
Marlin/src/libs/fatfs/sdio_driver.cpp

@ -59,13 +59,15 @@ uint8_t SD_Cmd(uint8_t cmd, uint32_t arg, uint16_t response_type, uint32_t *resp
return 0;
}
//#pragma GCC push_options
//#pragma GCC optimize ("O0")
uint32_t SD_transfer(uint8_t *buf, uint32_t blk, uint32_t cnt, uint32_t dir){
uint32_t trials;
uint8_t cmd=0;
uint8_t *ptr = buf;
if (SDCard.Type != SDCT_SDHC) {
blk = blk * 512;
}
trials=SDIO_DATA_TIMEOUT;
while (transmit && trials--) {};
if(!trials) {
@ -158,7 +160,6 @@ uint32_t SD_transfer(uint8_t *buf, uint32_t blk, uint32_t cnt, uint32_t dir){
SDIO->ICR=SDIO_ICR_STATIC;
return 0;
};
//#pragma GCC pop_options
uint8_t SD_Init(void) {
volatile uint32_t trials = 0x0000FFFF;
@ -199,6 +200,9 @@ uint8_t SD_Init(void) {
return 41;
};
SDCard.Type = (response[0] & SD_HIGH_CAPACITY) ? SDCT_SDHC : SDCT_SDSC_V2;
DEBUG("Card type %d",SDCard.Type);
result = SD_Cmd(SD_CMD2,0x00,SDIO_RESP_LONG,(uint32_t*)response); //CMD2 CID R2
if (result != 0) {
ERROR("CMD2: %d",result);
@ -270,6 +274,14 @@ uint8_t SD_Init(void) {
SDIO->CLKCR=tempreg;
#endif
if ((SDCard.Type != SDCT_SDHC)) {
result = SD_Cmd(SD_CMD_SET_BLOCKLEN, 512 ,SDIO_RESP_SHORT,(uint32_t*)response); //CMD16
if (result != 0) {
ERROR("Error set block size");
return 16;
}
}
DEBUG("SDINIT: ok");
return 0;
};

13
Marlin/src/libs/fatfs/sdio_driver.h

@ -60,12 +60,25 @@ typedef struct {
uint8_t ake_seq_error; //Ошибка в последовательности аутентификации.
} SD_Status_TypeDef;
// Card type
enum {
SDCT_UNKNOWN = 0x00,
SDCT_SDSC_V1 = 0x01, // Standard capacity SD card v1.0
SDCT_SDSC_V2 = 0x02, // Standard capacity SD card v2.0
SDCT_MMC = 0x03, // MMC
SDCT_SDHC = 0x04 // High capacity SD card (SDHC or SDXC)
};
#define SDIO_4BIT_Mode 1
//#define SDIO_HIGH_SPEED 1
#define SDIO_DATA_TIMEOUT ((uint32_t)0x01000000)
// Mask for ACMD41
#define SD_STD_CAPACITY ((uint32_t)0x00000000U)
#define SD_HIGH_CAPACITY ((uint32_t)0x40000000U)
// SDIO CMD response type
#define SDIO_RESP_NONE 0x00 // No response
#define SDIO_RESP_SHORT SDIO_CMD_WAITRESP_0 // Short response

7
Marlin/src/module/mks_wifi/mks_wifi.cpp

@ -30,6 +30,13 @@ void mks_wifi_init(void){
safe_delay(1000);
WRITE(MKS_WIFI_IO4, LOW);
#ifdef LIST_FILES_AT_STARTUP
mks_wifi_sd_deinit();
mks_wifi_sd_init();
mks_wifi_sd_ls();
mks_wifi_sd_deinit();
#endif
}

2
Marlin/src/module/mks_wifi/mks_wifi.h

@ -12,6 +12,8 @@
#define WIFI_MODE_AP (uint8_t)1
#define LIST_FILES_AT_STARTUP (uint8_t)1
typedef struct
{
uint8_t type;

14
Marlin/src/module/mks_wifi/mks_wifi_sd.cpp

@ -260,6 +260,20 @@ void mks_wifi_start_file_upload(ESP_PROTOC_FRAME *packet){
ui.set_status((const char *)"Upload done",true);
DEBUG("Upload ok");
BUZZ(1000,260);
str[0]='0';
str[1]=':';
str[2]='/';
memcpy((uint8_t *)str+3,(uint8_t *)&packet->data[5],(packet->dataLen - 5));
str[packet->dataLen - 5 + 3] = 0;
if(!strcmp(str,"0:/Robin_Nano35.bin")){
DEBUG("Firmware found, reboot");
nvic_sys_reset();
}
}else{
ui.set_status((const char *)"Upload failed",true);
DEBUG("Upload failed! File size: %d; Recieve %d; SD write %d",file_size,file_inc_size,file_size_writen);

129
Marlin/src/module/mks_wifi/small_cmsis.h

@ -142,6 +142,18 @@ typedef struct
__IO uint32_t MAPR2;
} AFIO_TypeDef;
typedef struct
{
__IO uint32_t CR1;
__IO uint32_t CR2;
__IO uint32_t SR;
__IO uint32_t DR;
__IO uint32_t CRCPR;
__IO uint32_t RXCRCR;
__IO uint32_t TXCRCR;
__IO uint32_t I2SCFGR;
__IO uint32_t I2SPR;
} SPI_TypeDef;
#define PERIPH_BASE 0x40000000U /*!< Peripheral base address in the alias region */
@ -161,7 +173,7 @@ typedef struct
#define AFIOBASE (APB2PERIPH_BASE + 0x00000000U)
#define CoreDebug_BASE (0xE000EDF0UL) /*!< Core Debug Base Address */
#define DWT_BASE (0xE0001000UL) /*!< DWT Base Address */
#define SPI2_BASE (APB1PERIPH_BASE + 0x00003800U)
#define RCC ((RCC_TypeDef *)RCC_BASE)
#define SDIO ((SDIO_TypeDef *)SDIO_BASE)
@ -177,6 +189,7 @@ typedef struct
#define AFIO ((AFIO_TypeDef *)AFIOBASE)
#define CoreDebug ((CoreDebug_Type *)CoreDebug_BASE) /*!< Core Debug configuration struct */
#define DWT ((DWT_Type *) DWT_BASE ) /*!< DWT configuration struct */
#define SPI2 ((SPI_TypeDef *)SPI2_BASE)
/******************************************************************************/
/* */
/* Universal Synchronous Asynchronous Receiver Transmitter */
@ -1708,5 +1721,119 @@ typedef struct
#define DWT_CTRL_CYCCNTENA_Pos 0U /*!< DWT CTRL: CYCCNTENA Position */
#define DWT_CTRL_CYCCNTENA_Msk (0x1UL /*<< DWT_CTRL_CYCCNTENA_Pos*/) /*!< DWT CTRL: CYCCNTENA Mask */
/******************************************************************************/
/* */
/* Serial Peripheral Interface */
/* */
/******************************************************************************/
/*
* @brief Specific device feature definitions (not present on all devices in the STM32F1 serie)
*/
#define SPI_I2S_SUPPORT /*!< I2S support */
/******************* Bit definition for SPI_CR1 register ********************/
#define SPI_CR1_CPHA_Pos (0U)
#define SPI_CR1_CPHA_Msk (0x1U << SPI_CR1_CPHA_Pos) /*!< 0x00000001 */
#define SPI_CR1_CPHA SPI_CR1_CPHA_Msk /*!< Clock Phase */
#define SPI_CR1_CPOL_Pos (1U)
#define SPI_CR1_CPOL_Msk (0x1U << SPI_CR1_CPOL_Pos) /*!< 0x00000002 */
#define SPI_CR1_CPOL SPI_CR1_CPOL_Msk /*!< Clock Polarity */
#define SPI_CR1_MSTR_Pos (2U)
#define SPI_CR1_MSTR_Msk (0x1U << SPI_CR1_MSTR_Pos) /*!< 0x00000004 */
#define SPI_CR1_MSTR SPI_CR1_MSTR_Msk /*!< Master Selection */
#define SPI_CR1_BR_Pos (3U)
#define SPI_CR1_BR_Msk (0x7U << SPI_CR1_BR_Pos) /*!< 0x00000038 */
#define SPI_CR1_BR SPI_CR1_BR_Msk /*!< BR[2:0] bits (Baud Rate Control) */
#define SPI_CR1_BR_0 (0x1U << SPI_CR1_BR_Pos) /*!< 0x00000008 */
#define SPI_CR1_BR_1 (0x2U << SPI_CR1_BR_Pos) /*!< 0x00000010 */
#define SPI_CR1_BR_2 (0x4U << SPI_CR1_BR_Pos) /*!< 0x00000020 */
#define SPI_CR1_SPE_Pos (6U)
#define SPI_CR1_SPE_Msk (0x1U << SPI_CR1_SPE_Pos) /*!< 0x00000040 */
#define SPI_CR1_SPE SPI_CR1_SPE_Msk /*!< SPI Enable */
#define SPI_CR1_LSBFIRST_Pos (7U)
#define SPI_CR1_LSBFIRST_Msk (0x1U << SPI_CR1_LSBFIRST_Pos) /*!< 0x00000080 */
#define SPI_CR1_LSBFIRST SPI_CR1_LSBFIRST_Msk /*!< Frame Format */
#define SPI_CR1_SSI_Pos (8U)
#define SPI_CR1_SSI_Msk (0x1U << SPI_CR1_SSI_Pos) /*!< 0x00000100 */
#define SPI_CR1_SSI SPI_CR1_SSI_Msk /*!< Internal slave select */
#define SPI_CR1_SSM_Pos (9U)
#define SPI_CR1_SSM_Msk (0x1U << SPI_CR1_SSM_Pos) /*!< 0x00000200 */
#define SPI_CR1_SSM SPI_CR1_SSM_Msk /*!< Software slave management */
#define SPI_CR1_RXONLY_Pos (10U)
#define SPI_CR1_RXONLY_Msk (0x1U << SPI_CR1_RXONLY_Pos) /*!< 0x00000400 */
#define SPI_CR1_RXONLY SPI_CR1_RXONLY_Msk /*!< Receive only */
#define SPI_CR1_DFF_Pos (11U)
#define SPI_CR1_DFF_Msk (0x1U << SPI_CR1_DFF_Pos) /*!< 0x00000800 */
#define SPI_CR1_DFF SPI_CR1_DFF_Msk /*!< Data Frame Format */
#define SPI_CR1_CRCNEXT_Pos (12U)
#define SPI_CR1_CRCNEXT_Msk (0x1U << SPI_CR1_CRCNEXT_Pos) /*!< 0x00001000 */
#define SPI_CR1_CRCNEXT SPI_CR1_CRCNEXT_Msk /*!< Transmit CRC next */
#define SPI_CR1_CRCEN_Pos (13U)
#define SPI_CR1_CRCEN_Msk (0x1U << SPI_CR1_CRCEN_Pos) /*!< 0x00002000 */
#define SPI_CR1_CRCEN SPI_CR1_CRCEN_Msk /*!< Hardware CRC calculation enable */
#define SPI_CR1_BIDIOE_Pos (14U)
#define SPI_CR1_BIDIOE_Msk (0x1U << SPI_CR1_BIDIOE_Pos) /*!< 0x00004000 */
#define SPI_CR1_BIDIOE SPI_CR1_BIDIOE_Msk /*!< Output enable in bidirectional mode */
#define SPI_CR1_BIDIMODE_Pos (15U)
#define SPI_CR1_BIDIMODE_Msk (0x1U << SPI_CR1_BIDIMODE_Pos) /*!< 0x00008000 */
#define SPI_CR1_BIDIMODE SPI_CR1_BIDIMODE_Msk /*!< Bidirectional data mode enable */
/******************* Bit definition for SPI_CR2 register ********************/
#define SPI_CR2_RXDMAEN_Pos (0U)
#define SPI_CR2_RXDMAEN_Msk (0x1U << SPI_CR2_RXDMAEN_Pos) /*!< 0x00000001 */
#define SPI_CR2_RXDMAEN SPI_CR2_RXDMAEN_Msk /*!< Rx Buffer DMA Enable */
#define SPI_CR2_TXDMAEN_Pos (1U)
#define SPI_CR2_TXDMAEN_Msk (0x1U << SPI_CR2_TXDMAEN_Pos) /*!< 0x00000002 */
#define SPI_CR2_TXDMAEN SPI_CR2_TXDMAEN_Msk /*!< Tx Buffer DMA Enable */
#define SPI_CR2_SSOE_Pos (2U)
#define SPI_CR2_SSOE_Msk (0x1U << SPI_CR2_SSOE_Pos) /*!< 0x00000004 */
#define SPI_CR2_SSOE SPI_CR2_SSOE_Msk /*!< SS Output Enable */
#define SPI_CR2_ERRIE_Pos (5U)
#define SPI_CR2_ERRIE_Msk (0x1U << SPI_CR2_ERRIE_Pos) /*!< 0x00000020 */
#define SPI_CR2_ERRIE SPI_CR2_ERRIE_Msk /*!< Error Interrupt Enable */
#define SPI_CR2_RXNEIE_Pos (6U)
#define SPI_CR2_RXNEIE_Msk (0x1U << SPI_CR2_RXNEIE_Pos) /*!< 0x00000040 */
#define SPI_CR2_RXNEIE SPI_CR2_RXNEIE_Msk /*!< RX buffer Not Empty Interrupt Enable */
#define SPI_CR2_TXEIE_Pos (7U)
#define SPI_CR2_TXEIE_Msk (0x1U << SPI_CR2_TXEIE_Pos) /*!< 0x00000080 */
#define SPI_CR2_TXEIE SPI_CR2_TXEIE_Msk /*!< Tx buffer Empty Interrupt Enable */
/******************** Bit definition for SPI_SR register ********************/
#define SPI_SR_RXNE_Pos (0U)
#define SPI_SR_RXNE_Msk (0x1U << SPI_SR_RXNE_Pos) /*!< 0x00000001 */
#define SPI_SR_RXNE SPI_SR_RXNE_Msk /*!< Receive buffer Not Empty */
#define SPI_SR_TXE_Pos (1U)
#define SPI_SR_TXE_Msk (0x1U << SPI_SR_TXE_Pos) /*!< 0x00000002 */
#define SPI_SR_TXE SPI_SR_TXE_Msk /*!< Transmit buffer Empty */
#define SPI_SR_CHSIDE_Pos (2U)
#define SPI_SR_CHSIDE_Msk (0x1U << SPI_SR_CHSIDE_Pos) /*!< 0x00000004 */
#define SPI_SR_CHSIDE SPI_SR_CHSIDE_Msk /*!< Channel side */
#define SPI_SR_UDR_Pos (3U)
#define SPI_SR_UDR_Msk (0x1U << SPI_SR_UDR_Pos) /*!< 0x00000008 */
#define SPI_SR_UDR SPI_SR_UDR_Msk /*!< Underrun flag */
#define SPI_SR_CRCERR_Pos (4U)
#define SPI_SR_CRCERR_Msk (0x1U << SPI_SR_CRCERR_Pos) /*!< 0x00000010 */
#define SPI_SR_CRCERR SPI_SR_CRCERR_Msk /*!< CRC Error flag */
#define SPI_SR_MODF_Pos (5U)
#define SPI_SR_MODF_Msk (0x1U << SPI_SR_MODF_Pos) /*!< 0x00000020 */
#define SPI_SR_MODF SPI_SR_MODF_Msk /*!< Mode fault */
#define SPI_SR_OVR_Pos (6U)
#define SPI_SR_OVR_Msk (0x1U << SPI_SR_OVR_Pos) /*!< 0x00000040 */
#define SPI_SR_OVR SPI_SR_OVR_Msk /*!< Overrun flag */
#define SPI_SR_BSY_Pos (7U)
#define SPI_SR_BSY_Msk (0x1U << SPI_SR_BSY_Pos) /*!< 0x00000080 */
#define SPI_SR_BSY SPI_SR_BSY_Msk /*!< Busy flag */
/******************** Bit definition for SPI_DR register ********************/
#define SPI_DR_DR_Pos (0U)
#define SPI_DR_DR_Msk (0xFFFFU << SPI_DR_DR_Pos) /*!< 0x0000FFFF */
#define SPI_DR_DR SPI_DR_DR_Msk /*!< Data Register */
/******************* Bit definition for SPI_CRCPR register ******************/
#define SPI_CRCPR_CRCPOLY_Pos (0U)
#define SPI_CRCPR_CRCPOLY_Msk (0xFFFFU << SPI_CRCPR_CRCPOLY_Pos) /*!< 0x0000FFFF */
#define SPI_CRCPR_CRCPOLY SPI_CRCPR_CRCPOLY_Msk /*!< CRC polynomial register */
#endif

1
Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO.h

@ -163,3 +163,4 @@
#define MKS_WIFI_IO4 PC7
#define MKS_WIFI_IO_RST PA5
#endif

158
README.md

@ -2,8 +2,11 @@
## Версия с тестовой поддержкой WIFI модуля
Это конфигурация [официального Marlin](https://github.com/MarlinFirmware/Marlin) для принтера Flying Bear Ghost 4S.
Это конфигурация [официального Marlin](https://github.com/MarlinFirmware/Marlin) для принтера Flying Bear Ghost 4S (плата MKS Robin Nano).
Эта ветка содержит код для работы с WIFI модулем, установленным в FB4S. Загрузка файлов через стандартный plugin в Cura.
Код работы с экраном взят из репозитория [inib/Marlin](https://github.com/inib/Marlin)
В ветке [FB4S_Config](https://github.com/Sergey1560/Marlin_FB4S/tree/FB4S_Config) находится вариант с минимальными изменениями в коде Marlin (только работа с экраном и конфигурация)
## Что работает, что не работает
@ -19,9 +22,8 @@
### Не работает (совсем)
* **Имена файлов на русском** Переименуйте файл в Cura
* Работает только с картами стандарта SDHC и новее. Это все карты от 4Гб и больше.
* Работает только с картами стандарта SD card v2.0 и новее. Это все карты от 1Гб и больше.
* Отображение состояния принтера (печатает, не печатает) в Cura
* Все остальное, что не в указано в "работает"
## Как работает, как настроить
@ -84,139 +86,65 @@ IP адрес так же будет на экране.
В качестве места хренения EEPROM в Marlin доступны несколько вариантов:
* SD карта. Этот вариант наиболее предпочтительный, если нет осознанного желания хранить EEPROM где-то еще.
* I2C EEPROM. Хранение в AT24C16 подключенной по I2C. При первом включении все содержимое AT24C16 будет переписано. Память не быстрая, поэтому процесс занимает до 10 секунд. В дальнейшем в память пишутся только измененные значения, поэтому работает быстрее.
* SPI_EEPROM. Хранение в W25Q64BV подключенной по SPI.
* FLASH_EEPROM_EMULATION. Это хранение EEPROM в flash памяти STM32. Этот вариант не работает.
* SRAM_EEPROM_EMULATION. Этот вариант не работает.
Для включения в [Configuration.h](./Marlin/Configuration.h) в разделе EEPROM должно быть включено SDCARD_EEPROM_EMULATION и отключены другие опции хранения. Пример:
Для включения в [Configuration.h](./Marlin/Configuration.h) в разделе EEPROM нужно указать нужный define. Возможные варианты указаны в комментарии. Пример:
```C
#define EEPROM_SETTINGS // Persistent storage with M500 and M501
#define EEPROM_CHITCHAT // Give feedback on EEPROM commands. Disable to save PROGMEM.
#if ENABLED(EEPROM_SETTINGS)
#define SDCARD_EEPROM_EMULATION
/*
MKS Robin EEPROM:
EEPROM_SD
EEPROM_AT24C16
EEPROM_W25Q
*/
#define EEPROM_SD
#if ENABLED(EEPROM_AT24C16)
#undef SDCARD_EEPROM_EMULATION
#undef USE_REAL_EEPROM
#undef FLASH_EEPROM_EMULATION
#undef SRAM_EEPROM_EMULATION
//#define USE_WIRED_EEPROM 1
//#define I2C_EEPROM_AT24C16
//#define E2END (2*1024 - 1)
#define EEPROM_AUTO_INIT // Init EEPROM automatically on any errors.
#define I2C_EEPROM_AT24C16
#define USE_WIRED_EEPROM 1
#define E2END (2*1024 - 1)
#endif
```
* I2C EEPROM. Для включения нужно включить I2C_EEPROM_AT24C16 и установить USE_WIRED_EEPROM в 1 и задать размер EEPROM в E2END, а остальные опции отключить. Пример:
```C
#define EEPROM_SETTINGS // Persistent storage with M500 and M501
#define EEPROM_CHITCHAT // Give feedback on EEPROM commands. Disable to save PROGMEM.
#if ENABLED(EEPROM_SETTINGS)
#if ENABLED(EEPROM_W25Q)
#undef SDCARD_EEPROM_EMULATION
#undef USE_REAL_EEPROM
#undef FLASH_EEPROM_EMULATION
#undef SRAM_EEPROM_EMULATION
#undef I2C_EEPROM_AT24C16
#define SPI_EEPROM_W25Q
#define SPI_EEPROM_OFFSET 0x700000
#define USE_WIRED_EEPROM 1
#define I2C_EEPROM_AT24C16
#define E2END (2*1024 - 1)
#define EEPROM_AUTO_INIT // Init EEPROM automatically on any errors.
#endif
```
При первом включении все содержимое AT24C16 будет переписано. Память не быстрая, поэтому процесс занимает до 10 секунд. В дальнейшем в память пишутся только измененные значения, поэтому работает быстрее.
* SPI_EEPROM. Хранение в памяти подключенной по SPI. Этот вариант пока не работает.
* FLASH_EEPROM_EMULATION. Это хранение EEPROM в flash памяти STM32. Этот вариант не работает.
* SRAM_EEPROM_EMULATION. Этот вариант не работает.
### Работа с Octoprint
При работе с Octoprint через Uart возможны проблемы при печати. Рекомендуется, увеличить буферы команд в настройках Marlin [Configuration_adv.h](./Marlin/Configuration_adv.h):
```C
#define MAX_CMD_SIZE 96 //Максимальный размер команды
#define BUFSIZE 32 //Количество команд, которые стоят в плане.
#define TX_BUFFER_SIZE 256 //Размер буфера для отправки
#define RX_BUFFER_SIZE 2048 //Размер буфера для приема
```
Процесс получения данных из UART организован следующим образом:
* используется аппаратный UART STM32
* включено прерывание по приему каждого байта, данные складываются в буфер внутри драйвера
* Marlin периодически проверяет, есть ли у драйвера в буфере данные, забирает их оттуда и складывает в свой буфер, который задан RX_BUFFER_SIZE.
Есть предположение, что проблемы печати могут быть связаны с тем, что переполняется буфер внутри драйвера. В качестве драйвера использована библиотека libmaple. Обработчик прерывания в файле .platformio/packages/framework-arduinoststm32-maple/STM32F1/system/libmaple/usart_private.h:
```C
__weak void __irq_usart1(void) {
usart_irq(&usart1_rb, &usart1_wb, USART1_BASE);
}
```
В обработчике usart_irq (в файле .platformio/packages/framework-arduinoststm32-maple/STM32F1/system/libmaple/usart_private.h) пришедший байт помещается в буфер функцией
```C
rb_push_insert(rb, (uint8)regs->DR);
```
rb имеет тип структуры ring_buffer:
```C
typedef struct ring_buffer {
volatile uint8 *buf; /**< Buffer items are stored into */
volatile uint16 head; /**< Index of the next item to remove */
volatile uint16 tail; /**< Index where the next item will get inserted */
volatile uint16 size; /**< Buffer capacity minus one */
} ring_buffer;
```
Сам приемный буфер и его размер задается в .platformio/packages/framework-arduinoststm32-maple/STM32F1/system/libmaple/include/libmaple/usart.h:
```C
typedef struct usart_dev {
usart_reg_map *regs; /**< Register map */
ring_buffer *rb; /**< RX ring buffer */
ring_buffer *wb; /**< TX ring buffer */
uint32 max_baud; /**< @brief Deprecated.
* Maximum baud rate. */
uint8 rx_buf[USART_RX_BUF_SIZE]; /**< @brief Deprecated.
* Actual RX buffer used by rb.
* This field will be removed in
* a future release. */
uint8 tx_buf[USART_TX_BUF_SIZE]; /**< Actual TX buffer used by wb */
rcc_clk_id clk_id; /**< RCC clock information */
nvic_irq_num irq_num; /**< USART NVIC interrupt */
} usart_dev;
```
Размер массива задан при помощи USART_RX_BUF_SIZE и USART_TX_BUF_SIZE:
```C
#ifndef USART_RX_BUF_SIZE
#define USART_RX_BUF_SIZE 64
#if ENABLED(EEPROM_SD)
#define SDCARD_EEPROM_EMULATION
#undef USE_REAL_EEPROM
#undef FLASH_EEPROM_EMULATION
#undef SRAM_EEPROM_EMULATION
#undef I2C_EEPROM_AT24C16
#undef SPI_EEPROM_W25Q
#undef USE_WIRED_EEPROM
#endif
#ifndef USART_TX_BUF_SIZE
#define USART_TX_BUF_SIZE 64
#define EEPROM_AUTO_INIT // Init EEPROM automatically on any errors.
#endif
```
Для успешной работы Octoprint возможно имеет смысл увеличить эти значения. Например до 1024. Это предположение не тестировалось на практике. Возможно, одновременно с увеличением размера буферов в драйвере поможет и увеличение скорости UART до 250000.
Для изменения места хранения EEPROM например на SPI флеш, надо заменить "#define EEPROM_SD" на "#define EEPROM_W25Q"
Библиотека libmaple находится внутри platformio, и обновляется автоматически. Поэтому, чтобы не изменять стандартные файлы библиотеки и не потерять изменения при обновлении бибилиотеки, задать параметры лучше через флаги сборки. В файле [platformio.ini](./platformio.ini), в разделе mks_robin_nano надо добавить в build_flags параметры USART_RX_BUF_SIZE и USART_TX_BUF_SIZE. Пример:
### Загрузка прошивки по WIFI
```C
#
# MKS Robin Nano (STM32F103VET6)
#
[env:mks_robin_nano]
platform = ststm32
board = genericSTM32F103VE
platform_packages = tool-stm32duino
build_flags = !python Marlin/src/HAL/STM32F1/build_flags.py
${common.build_flags} -std=gnu++14 -DHAVE_SW_SERIAL -DSS_TIMER=4 -DUSART_RX_BUF_SIZE=1024 -DUSART_TX_BUF_SIZE=1024
build_unflags = -std=gnu++11
extra_scripts = buildroot/share/PlatformIO/scripts/mks_robin_nano.py
src_filter = ${common.default_src_filter} +<src/HAL/STM32F1>
lib_deps = ${common.lib_deps}
SoftwareSerialM=https://github.com/FYSETC/SoftwareSerialM/archive/master.zip
lib_ignore = Adafruit NeoPixel, SPI
```
Есть возможность отправлять прошивку на принтер через WIFI. Для этого в файле [platformio.ini](./platformio.ini) в разделе "[env:mks_robin_nano]" нужно указать IP адрес принтера в опции upload_flags (строка 499).
Передача файла происходит при помощи curl, поэтому надо или добавить curl в $PATH, либо указать полный путь в файле [mks_robin_nano.py](./buildroot/share/PlatformIO/scripts/mks_robin_nano.py) в строке 48.
После успешной передачи файла принтер перезагрузится автоматически.

6
buildroot/share/PlatformIO/scripts/mks_robin_nano.py

@ -42,3 +42,9 @@ def encrypt(source, target, env):
destination = target[0].dir.path +'/Robin_nano35.bin'
shutil.copyfile(source, destination)
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", encrypt);
env.Replace(
UPLOADER="curl",
UPLOADCMD="$UPLOADER -v -H 'Content-Type:application/octet-stream' http://$UPLOADERFLAGS/upload?X-Filename=Robin_Nano35.bin --data-binary @$BUILD_DIR/Robin_nano35.bin"
)

BIN
firmware/2208/Robin_nano35.bin

Binary file not shown.

BIN
firmware/bootloader/fb_4s_bootloader.bin

Binary file not shown.

BIN
firmware/std/Robin_nano35.bin

Binary file not shown.

4
platformio.ini

@ -494,7 +494,9 @@ src_filter = ${common.default_src_filter} +<src/HAL/STM32F1>
lib_deps = ${common.lib_deps}
SoftwareSerialM=https://github.com/FYSETC/SoftwareSerialM/archive/master.zip
lib_ignore = Adafruit NeoPixel, SPI
upload_protocol = custom
upload_flags =
192.168.0.107
#
# MKS Robin (STM32F103ZET6)
#

Loading…
Cancel
Save