Standardize Marlin SPI (part 1) (#19989)
This commit is contained in:
		
							parent
							
								
									97d7af7a23
								
							
						
					
					
						commit
						85d094bbb4
					
				
							
								
								
									
										1
									
								
								.github/workflows/test-builds.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/workflows/test-builds.yml
									
									
									
									
										vendored
									
									
								
							| @ -83,6 +83,7 @@ jobs: | ||||
|         - STM32F103RET6_creality | ||||
|         - LERDGEX | ||||
|         - mks_robin_nano35 | ||||
|         - mks_robin_nano35_stm32 | ||||
|         - NUCLEO_F767ZI | ||||
| 
 | ||||
|         # Put lengthy tests last | ||||
|  | ||||
| @ -127,11 +127,9 @@ | ||||
|     for (uint16_t i = 0; i < nbyte; i++) doio(buf[i]); | ||||
|   } | ||||
| 
 | ||||
|   void spiSend(uint32_t chan, byte b) { | ||||
|   } | ||||
|   void spiSend(uint32_t chan, byte b) {} | ||||
| 
 | ||||
|   void spiSend(uint32_t chan, const uint8_t* buf, size_t nbyte) { | ||||
|   } | ||||
|   void spiSend(uint32_t chan, const uint8_t* buf, size_t nbyte) {} | ||||
| 
 | ||||
|   // Read single byte from SPI
 | ||||
|   uint8_t spiRec() { return doio(0xFF); } | ||||
| @ -143,9 +141,7 @@ | ||||
|     for (uint16_t i = 0; i < nbyte; i++) buf[i] = doio(0xFF); | ||||
|   } | ||||
| 
 | ||||
|   uint8_t spiTransfer(uint8_t b) { | ||||
|     return doio(b); | ||||
|   } | ||||
|   uint8_t spiTransfer(uint8_t b) { return doio(b); } | ||||
| 
 | ||||
|   // Write from buffer to SPI
 | ||||
|   void spiSendBlock(uint8_t token, const uint8_t* buf) { | ||||
| @ -201,6 +197,15 @@ SPIClass::SPIClass(uint8_t device) { | ||||
|   GPDMA_Init(); | ||||
| } | ||||
| 
 | ||||
| SPIClass::SPIClass(pin_t mosi, pin_t miso, pin_t sclk, pin_t ssel) { | ||||
|   #if BOARD_NR_SPI >= 1 | ||||
|     if (mosi == BOARD_SPI1_MOSI_PIN) SPIClass(1); | ||||
|   #endif | ||||
|   #if BOARD_NR_SPI >= 2 | ||||
|     if (mosi == BOARD_SPI2_MOSI_PIN) SPIClass(2); | ||||
|   #endif | ||||
| } | ||||
| 
 | ||||
| void SPIClass::begin() { | ||||
|   // Init the SPI pins in the first begin call
 | ||||
|   if ((_currentSetting->spi_d == LPC_SSP0 && spiInitialised[0] == false) || | ||||
| @ -331,25 +336,15 @@ void SPIClass::read(uint8_t *buf, uint32_t len) { | ||||
|   for (uint16_t i = 0; i < len; i++) buf[i] = transfer(0xFF); | ||||
| } | ||||
| 
 | ||||
| void SPIClass::setClock(uint32_t clock) { | ||||
|   _currentSetting->clock = clock; | ||||
| } | ||||
| void SPIClass::setClock(uint32_t clock) { _currentSetting->clock = clock; } | ||||
| 
 | ||||
| void SPIClass::setModule(uint8_t device) { | ||||
|   _currentSetting = &_settings[device - 1];// SPI channels are called 1 2 and 3 but the array is zero indexed
 | ||||
| } | ||||
| void SPIClass::setModule(uint8_t device) { _currentSetting = &_settings[device - 1]; } // SPI channels are called 1, 2, and 3 but the array is zero-indexed
 | ||||
| 
 | ||||
| void SPIClass::setBitOrder(uint8_t bitOrder) { | ||||
|   _currentSetting->bitOrder = bitOrder; | ||||
| } | ||||
| void SPIClass::setBitOrder(uint8_t bitOrder) { _currentSetting->bitOrder = bitOrder; } | ||||
| 
 | ||||
| void SPIClass::setDataMode(uint8_t dataMode) { | ||||
|   _currentSetting->dataMode = dataMode; | ||||
| } | ||||
| void SPIClass::setDataMode(uint8_t dataMode) { _currentSetting->dataMode = dataMode; } | ||||
| 
 | ||||
| void SPIClass::setDataSize(uint32_t ds) { | ||||
|   _currentSetting->dataSize = ds; | ||||
| } | ||||
| void SPIClass::setDataSize(uint32_t dataSize) { _currentSetting->dataSize = dataSize; } | ||||
| 
 | ||||
| /**
 | ||||
|  * Set up/tear down | ||||
|  | ||||
							
								
								
									
										45
									
								
								Marlin/src/HAL/LPC1768/MarlinSPI.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								Marlin/src/HAL/LPC1768/MarlinSPI.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | ||||
| /**
 | ||||
|  * 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 <https://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  */ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <SPI.h> | ||||
| 
 | ||||
| /**
 | ||||
|  * Marlin currently requires 3 SPI classes: | ||||
|  * | ||||
|  * SPIClass: | ||||
|  *  This class is normally provided by frameworks and has a semi-default interface. | ||||
|  *  This is needed because some libraries reference it globally. | ||||
|  * | ||||
|  * SPISettings: | ||||
|  *  Container for SPI configs for SPIClass. As above, libraries may reference it globally. | ||||
|  * | ||||
|  * These two classes are often provided by frameworks so we cannot extend them to add | ||||
|  * useful methods for Marlin. | ||||
|  * | ||||
|  * MarlinSPI: | ||||
|  *  Provides the default SPIClass interface plus some Marlin goodies such as a simplified | ||||
|  *  interface for SPI DMA transfer. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| using MarlinSPI = SPIClass; | ||||
| @ -126,6 +126,11 @@ public: | ||||
|    */ | ||||
|   SPIClass(uint8_t spiPortNumber); | ||||
| 
 | ||||
|   /**
 | ||||
|    * Init using pins | ||||
|    */ | ||||
|   SPIClass(pin_t mosi, pin_t miso, pin_t sclk, pin_t ssel = (pin_t)-1); | ||||
| 
 | ||||
|   /**
 | ||||
|    * Select and configure the current selected SPI device to use | ||||
|    */ | ||||
|  | ||||
							
								
								
									
										161
									
								
								Marlin/src/HAL/STM32/MarlinSPI.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								Marlin/src/HAL/STM32/MarlinSPI.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,161 @@ | ||||
| /**
 | ||||
|  * 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 <https://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include "MarlinSPI.h" | ||||
| 
 | ||||
| static void spi_init(spi_t *obj, uint32_t speed, spi_mode_e mode, uint8_t msb, uint32_t dataSize) { | ||||
|   spi_init(obj, speed, mode, msb); | ||||
|   // spi_init set 8bit always
 | ||||
|   // TODO: copy the code from spi_init and handle data size, to avoid double init always!!
 | ||||
|   if (dataSize != SPI_DATASIZE_8BIT) { | ||||
|     obj->handle.Init.DataSize = dataSize; | ||||
|     HAL_SPI_Init(&obj->handle); | ||||
|     __HAL_SPI_ENABLE(&obj->handle); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void MarlinSPI::setClockDivider(uint8_t _div) { | ||||
|   _speed = spi_getClkFreq(&_spi);// / _div;
 | ||||
|   _clockDivider = _div; | ||||
| } | ||||
| 
 | ||||
| void MarlinSPI::begin(void) { | ||||
|   //TODO: only call spi_init if any parameter changed!!
 | ||||
|   spi_init(&_spi, _speed, _dataMode, _bitOrder, _dataSize); | ||||
| } | ||||
| 
 | ||||
| void MarlinSPI::setupDma(SPI_HandleTypeDef &_spiHandle, DMA_HandleTypeDef &_dmaHandle, uint32_t direction, bool minc) { | ||||
|   _dmaHandle.Init.Direction = direction; | ||||
|   _dmaHandle.Init.PeriphInc = DMA_PINC_DISABLE; | ||||
|   _dmaHandle.Init.Mode = DMA_NORMAL; | ||||
|   _dmaHandle.Init.Priority = DMA_PRIORITY_LOW; | ||||
|   _dmaHandle.Init.MemInc = minc ? DMA_MINC_ENABLE : DMA_MINC_DISABLE; | ||||
| 
 | ||||
|   if (_dataSize == DATA_SIZE_8BIT) { | ||||
|     _dmaHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; | ||||
|     _dmaHandle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; | ||||
|   } | ||||
|   else { | ||||
|     _dmaHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; | ||||
|     _dmaHandle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; | ||||
|   } | ||||
|   #ifdef STM32F4xx | ||||
|     _dmaHandle.Init.Channel = DMA_CHANNEL_3; | ||||
|     _dmaHandle.Init.FIFOMode = DMA_FIFOMODE_DISABLE; | ||||
|   #endif | ||||
| 
 | ||||
|   // start DMA hardware
 | ||||
|   // TODO: check if hardware is already enabled
 | ||||
|   #ifdef SPI1_BASE | ||||
|     if (_spiHandle.Instance == SPI1) { | ||||
|       #ifdef STM32F1xx | ||||
|         __HAL_RCC_DMA1_CLK_ENABLE(); | ||||
|         _dmaHandle.Instance = (direction == DMA_MEMORY_TO_PERIPH) ? DMA1_Channel3 : DMA1_Channel2; | ||||
|       #elif defined(STM32F4xx) | ||||
|         __HAL_RCC_DMA2_CLK_ENABLE(); | ||||
|         _dmaHandle.Instance = DMA2_Stream3; | ||||
|       #endif | ||||
|     } | ||||
|   #endif | ||||
|   #ifdef SPI2_BASE | ||||
|     if (_spiHandle.Instance == SPI2) { | ||||
|       #ifdef STM32F1xx | ||||
|         __HAL_RCC_DMA1_CLK_ENABLE(); | ||||
|         _dmaHandle.Instance = (direction == DMA_MEMORY_TO_PERIPH) ? DMA1_Channel5 : DMA1_Channel4; | ||||
|       #elif defined(STM32F4xx) | ||||
|         //TODO: f4 dma config
 | ||||
|       #endif | ||||
|     } | ||||
|   #endif | ||||
|   #ifdef SPI3_BASE | ||||
|     if (_spiHandle.Instance == SPI3) { | ||||
|       #ifdef STM32F1xx | ||||
|         __HAL_RCC_DMA2_CLK_ENABLE(); | ||||
|         _dmaHandle.Instance = (direction == DMA_MEMORY_TO_PERIPH) ? DMA2_Channel2 : DMA2_Channel1; | ||||
|       #elif defined(STM32F4xx) | ||||
|         //TODO: f4 dma config
 | ||||
|       #endif | ||||
|     } | ||||
|   #endif | ||||
| 
 | ||||
|   HAL_DMA_Init(&_dmaHandle); | ||||
| } | ||||
| 
 | ||||
| byte MarlinSPI::transfer(uint8_t _data) { | ||||
|   uint8_t rxData = 0xFF; | ||||
|   HAL_SPI_TransmitReceive(&_spi.handle, &_data, &rxData, 1, HAL_MAX_DELAY); | ||||
|   return rxData; | ||||
| } | ||||
| 
 | ||||
| uint8_t MarlinSPI::dmaTransfer(const void *transmitBuf, void *receiveBuf, uint16_t length) { | ||||
|   const uint8_t ff = 0xFF; | ||||
| 
 | ||||
|   //if ((hspi->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE) //only enable if disabled
 | ||||
|   __HAL_SPI_ENABLE(&_spi.handle); | ||||
| 
 | ||||
|   if (receiveBuf) { | ||||
|     setupDma(_spi.handle, _dmaRx, DMA_PERIPH_TO_MEMORY, true); | ||||
|     HAL_DMA_Start(&_dmaRx, (uint32_t)&(_spi.handle.Instance->DR), (uint32_t)receiveBuf, length); | ||||
|     SET_BIT(_spi.handle.Instance->CR2, SPI_CR2_RXDMAEN); /* Enable Rx DMA Request */ | ||||
|   } | ||||
| 
 | ||||
|   // check for 2 lines transfer
 | ||||
|   bool mincTransmit = true; | ||||
|   if (transmitBuf == nullptr && _spi.handle.Init.Direction == SPI_DIRECTION_2LINES && _spi.handle.Init.Mode == SPI_MODE_MASTER) { | ||||
|     transmitBuf = &ff; | ||||
|     mincTransmit = false; | ||||
|   } | ||||
| 
 | ||||
|   if (transmitBuf) { | ||||
|     setupDma(_spi.handle, _dmaTx, DMA_MEMORY_TO_PERIPH, mincTransmit); | ||||
|     HAL_DMA_Start(&_dmaTx, (uint32_t)transmitBuf, (uint32_t)&(_spi.handle.Instance->DR), length); | ||||
|     SET_BIT(_spi.handle.Instance->CR2, SPI_CR2_TXDMAEN);   /* Enable Tx DMA Request */ | ||||
|   } | ||||
| 
 | ||||
|   if (transmitBuf) { | ||||
|     HAL_DMA_PollForTransfer(&_dmaTx, HAL_DMA_FULL_TRANSFER, HAL_MAX_DELAY); | ||||
|     HAL_DMA_Abort(&_dmaTx); | ||||
|     HAL_DMA_DeInit(&_dmaTx); | ||||
|   } | ||||
| 
 | ||||
|   // while ((_spi.handle.Instance->SR & SPI_FLAG_RXNE) != SPI_FLAG_RXNE) {}
 | ||||
| 
 | ||||
|   if (receiveBuf) { | ||||
|     HAL_DMA_PollForTransfer(&_dmaRx, HAL_DMA_FULL_TRANSFER, HAL_MAX_DELAY); | ||||
|     HAL_DMA_Abort(&_dmaRx); | ||||
|     HAL_DMA_DeInit(&_dmaRx); | ||||
|   } | ||||
| 
 | ||||
|   return 1; | ||||
| } | ||||
| 
 | ||||
| uint8_t MarlinSPI::dmaSend(const void * transmitBuf, uint16_t length, bool minc) { | ||||
|   setupDma(_spi.handle, _dmaTx, DMA_MEMORY_TO_PERIPH, minc); | ||||
|   HAL_DMA_Start(&_dmaTx, (uint32_t)transmitBuf, (uint32_t)&(_spi.handle.Instance->DR), length); | ||||
|   __HAL_SPI_ENABLE(&_spi.handle); | ||||
|   SET_BIT(_spi.handle.Instance->CR2, SPI_CR2_TXDMAEN);   /* Enable Tx DMA Request */ | ||||
|   HAL_DMA_PollForTransfer(&_dmaTx, HAL_DMA_FULL_TRANSFER, HAL_MAX_DELAY); | ||||
|   HAL_DMA_Abort(&_dmaTx); | ||||
|   // DeInit objects
 | ||||
|   HAL_DMA_DeInit(&_dmaTx); | ||||
|   return 1; | ||||
| } | ||||
							
								
								
									
										107
									
								
								Marlin/src/HAL/STM32/MarlinSPI.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								Marlin/src/HAL/STM32/MarlinSPI.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,107 @@ | ||||
| /**
 | ||||
|  * 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 <https://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  */ | ||||
| #pragma once | ||||
| 
 | ||||
| #include "HAL.h" | ||||
| #include <SPI.h> | ||||
| 
 | ||||
| extern "C" { | ||||
|   #include <utility/spi_com.h> | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Marlin currently requires 3 SPI classes: | ||||
|  * | ||||
|  * SPIClass: | ||||
|  *  This class is normally provided by frameworks and has a semi-default interface. | ||||
|  *  This is needed because some libraries reference it globally. | ||||
|  * | ||||
|  * SPISettings: | ||||
|  *  Container for SPI configs for SPIClass. As above, libraries may reference it globally. | ||||
|  * | ||||
|  * These two classes are often provided by frameworks so we cannot extend them to add | ||||
|  * useful methods for Marlin. | ||||
|  * | ||||
|  * MarlinSPI: | ||||
|  *  Provides the default SPIClass interface plus some Marlin goodies such as a simplified | ||||
|  *  interface for SPI DMA transfer. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #define DATA_SIZE_8BIT SPI_DATASIZE_8BIT | ||||
| #define DATA_SIZE_16BIT SPI_DATASIZE_16BIT | ||||
| 
 | ||||
| class MarlinSPI { | ||||
| public: | ||||
|   MarlinSPI() : MarlinSPI(NC, NC, NC, NC) {} | ||||
| 
 | ||||
|   MarlinSPI(pin_t mosi, pin_t miso, pin_t sclk, pin_t ssel = (pin_t)NC) : _mosiPin(mosi), _misoPin(miso), _sckPin(sclk), _ssPin(ssel) { | ||||
|     _spi.pin_miso = digitalPinToPinName(_misoPin); | ||||
|     _spi.pin_mosi = digitalPinToPinName(_mosiPin); | ||||
|     _spi.pin_sclk = digitalPinToPinName(_sckPin); | ||||
|     _spi.pin_ssel = digitalPinToPinName(_ssPin); | ||||
|     _dataSize = DATA_SIZE_8BIT; | ||||
|     _bitOrder = MSBFIRST; | ||||
|     _dataMode = SPI_MODE_0; | ||||
|     _spi.handle.State = HAL_SPI_STATE_RESET; | ||||
|     setClockDivider(SPI_SPEED_CLOCK_DIV2_MHZ); | ||||
|   } | ||||
| 
 | ||||
|   void begin(void); | ||||
|   void end(void) {} | ||||
| 
 | ||||
|   byte transfer(uint8_t _data); | ||||
|   uint8_t dmaTransfer(const void *transmitBuf, void *receiveBuf, uint16_t length); | ||||
|   uint8_t dmaSend(const void * transmitBuf, uint16_t length, bool minc = true); | ||||
| 
 | ||||
|   /* These methods are deprecated and kept for compatibility.
 | ||||
|    * Use SPISettings with SPI.beginTransaction() to configure SPI parameters. | ||||
|    */ | ||||
|   void setBitOrder(BitOrder _order) { _bitOrder = _order; } | ||||
| 
 | ||||
|   void setDataMode(uint8_t _mode) { | ||||
|     switch (_mode) { | ||||
|       case SPI_MODE0: _dataMode = SPI_MODE_0; break; | ||||
|       case SPI_MODE1: _dataMode = SPI_MODE_1; break; | ||||
|       case SPI_MODE2: _dataMode = SPI_MODE_2; break; | ||||
|       case SPI_MODE3: _dataMode = SPI_MODE_3; break; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   void setClockDivider(uint8_t _div); | ||||
| 
 | ||||
| private: | ||||
|   void setupDma(SPI_HandleTypeDef &_spiHandle, DMA_HandleTypeDef &_dmaHandle, uint32_t direction, bool minc = false); | ||||
| 
 | ||||
|   spi_t _spi; | ||||
|   DMA_HandleTypeDef _dmaTx; | ||||
|   DMA_HandleTypeDef _dmaRx; | ||||
|   BitOrder _bitOrder; | ||||
|   spi_mode_e _dataMode; | ||||
|   uint8_t _clockDivider; | ||||
|   uint32_t _speed; | ||||
|   uint32_t _dataSize; | ||||
|   pin_t _mosiPin; | ||||
|   pin_t _misoPin; | ||||
|   pin_t _sckPin; | ||||
|   pin_t _ssPin; | ||||
| }; | ||||
| @ -105,7 +105,7 @@ void SetTimerInterruptPriorities(); | ||||
| 
 | ||||
| // FORCE_INLINE because these are used in performance-critical situations
 | ||||
| FORCE_INLINE bool HAL_timer_initialized(const uint8_t timer_num) { | ||||
|   return timer_instance[timer_num] != NULL; | ||||
|   return timer_instance[timer_num] != nullptr; | ||||
| } | ||||
| FORCE_INLINE static hal_timer_t HAL_timer_get_count(const uint8_t timer_num) { | ||||
|   return HAL_timer_initialized(timer_num) ? timer_instance[timer_num]->getCount() : 0; | ||||
|  | ||||
							
								
								
									
										45
									
								
								Marlin/src/HAL/STM32F1/MarlinSPI.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								Marlin/src/HAL/STM32F1/MarlinSPI.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | ||||
| /**
 | ||||
|  * 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 <https://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  */ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <SPI.h> | ||||
| 
 | ||||
| /**
 | ||||
|  * Marlin currently requires 3 SPI classes: | ||||
|  * | ||||
|  * SPIClass: | ||||
|  *  This class is normally provided by frameworks and has a semi-default interface. | ||||
|  *  This is needed because some libraries reference it globally. | ||||
|  * | ||||
|  * SPISettings: | ||||
|  *  Container for SPI configs for SPIClass. As above, libraries may reference it globally. | ||||
|  * | ||||
|  * These two classes are often provided by frameworks so we cannot extend them to add | ||||
|  * useful methods for Marlin. | ||||
|  * | ||||
|  * MarlinSPI: | ||||
|  *  Provides the default SPIClass interface plus some Marlin goodies such as a simplified | ||||
|  *  interface for SPI DMA transfer. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| using MarlinSPI = SPIClass; | ||||
| @ -147,6 +147,18 @@ SPIClass::SPIClass(uint32_t spi_num) { | ||||
|   _currentSetting->state = SPI_STATE_IDLE; | ||||
| } | ||||
| 
 | ||||
| SPIClass::SPIClass(int8_t mosi, int8_t miso, int8_t sclk, int8_t ssel) { | ||||
|   #if BOARD_NR_SPI >= 1 | ||||
|     if (mosi == BOARD_SPI1_MOSI_PIN) SPIClass(1); | ||||
|   #endif | ||||
|   #if BOARD_NR_SPI >= 2 | ||||
|     if (mosi == BOARD_SPI2_MOSI_PIN) SPIClass(2); | ||||
|   #endif | ||||
|   #if BOARD_NR_SPI >= 3 | ||||
|     if (mosi == BOARD_SPI3_MOSI_PIN) SPIClass(3); | ||||
|   #endif | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Set up/tear down | ||||
|  */ | ||||
|  | ||||
| @ -163,6 +163,11 @@ public: | ||||
|    */ | ||||
|   SPIClass(uint32_t spiPortNumber); | ||||
| 
 | ||||
|   /**
 | ||||
|    * Init using pins | ||||
|    */ | ||||
|   SPIClass(int8_t mosi, int8_t miso, int8_t sclk, int8_t ssel=-1); | ||||
| 
 | ||||
|   /**
 | ||||
|    * @brief Equivalent to begin(SPI_1_125MHZ, MSBFIRST, 0). | ||||
|    */ | ||||
|  | ||||
| @ -32,7 +32,12 @@ | ||||
| 
 | ||||
| /**
 | ||||
|  * lcd_put_u8str_ind_P | ||||
|  * Print a string with an index substituted within it | ||||
|  * | ||||
|  * Print a string with an index substituted within it: | ||||
|  * | ||||
|  *   = displays  '0'....'10' for indexes 0 - 10 | ||||
|  *   ~ displays  '1'....'11' for indexes 0 - 10 | ||||
|  *   * displays 'E1'...'E11' for indexes 0 - 10 (By default. Uses LCD_FIRST_TOOL) | ||||
|  */ | ||||
| lcd_uint_t lcd_put_u8str_ind_P(PGM_P const pstr, const int8_t ind, PGM_P const inStr/*=nullptr*/, const lcd_uint_t maxlen/*=LCD_WIDTH*/) { | ||||
|   uint8_t *p = (uint8_t*)pstr; | ||||
|  | ||||
| @ -44,21 +44,21 @@ void TFT_String::set_font(const uint8_t *font) { | ||||
| 
 | ||||
|   for (glyph = 0; glyph < 256; glyph++) glyphs[glyph] = nullptr; | ||||
| 
 | ||||
|   DEBUG_ECHOLNPAIR("Format: ", font_header->Format); | ||||
|   DEBUG_ECHOLNPAIR("BBXWidth: ", font_header->BBXWidth); | ||||
|   DEBUG_ECHOLNPAIR("BBXHeight: ", font_header->BBXHeight); | ||||
|   DEBUG_ECHOLNPAIR("BBXOffsetX: ", font_header->BBXOffsetX); | ||||
|   DEBUG_ECHOLNPAIR("BBXOffsetY: ", font_header->BBXOffsetY); | ||||
|   DEBUG_ECHOLNPAIR("CapitalAHeight: ", font_header->CapitalAHeight); | ||||
|   DEBUG_ECHOLNPAIR("Encoding65Pos: ", font_header->Encoding65Pos); | ||||
|   DEBUG_ECHOLNPAIR("Encoding97Pos: ", font_header->Encoding97Pos); | ||||
|   DEBUG_ECHOLNPAIR("Format: ",            font_header->Format); | ||||
|   DEBUG_ECHOLNPAIR("BBXWidth: ",          font_header->BBXWidth); | ||||
|   DEBUG_ECHOLNPAIR("BBXHeight: ",         font_header->BBXHeight); | ||||
|   DEBUG_ECHOLNPAIR("BBXOffsetX: ",        font_header->BBXOffsetX); | ||||
|   DEBUG_ECHOLNPAIR("BBXOffsetY: ",        font_header->BBXOffsetY); | ||||
|   DEBUG_ECHOLNPAIR("CapitalAHeight: ",    font_header->CapitalAHeight); | ||||
|   DEBUG_ECHOLNPAIR("Encoding65Pos: ",     font_header->Encoding65Pos); | ||||
|   DEBUG_ECHOLNPAIR("Encoding97Pos: ",     font_header->Encoding97Pos); | ||||
|   DEBUG_ECHOLNPAIR("FontStartEncoding: ", font_header->FontStartEncoding); | ||||
|   DEBUG_ECHOLNPAIR("FontEndEncoding: ", font_header->FontEndEncoding); | ||||
|   DEBUG_ECHOLNPAIR("LowerGDescent: ", font_header->LowerGDescent); | ||||
|   DEBUG_ECHOLNPAIR("FontAscent: ", font_header->FontAscent); | ||||
|   DEBUG_ECHOLNPAIR("FontDescent: ", font_header->FontDescent); | ||||
|   DEBUG_ECHOLNPAIR("FontXAscent: ", font_header->FontXAscent); | ||||
|   DEBUG_ECHOLNPAIR("FontXDescent: ", font_header->FontXDescent); | ||||
|   DEBUG_ECHOLNPAIR("FontEndEncoding: ",   font_header->FontEndEncoding); | ||||
|   DEBUG_ECHOLNPAIR("LowerGDescent: ",     font_header->LowerGDescent); | ||||
|   DEBUG_ECHOLNPAIR("FontAscent: ",        font_header->FontAscent); | ||||
|   DEBUG_ECHOLNPAIR("FontDescent: ",       font_header->FontDescent); | ||||
|   DEBUG_ECHOLNPAIR("FontXAscent: ",       font_header->FontXAscent); | ||||
|   DEBUG_ECHOLNPAIR("FontXDescent: ",      font_header->FontXDescent); | ||||
| 
 | ||||
|   add_glyphs(font); | ||||
| } | ||||
| @ -72,9 +72,8 @@ void TFT_String::add_glyphs(const uint8_t *font) { | ||||
|       glyphs[glyph] = (glyph_t *)pointer; | ||||
|       pointer += sizeof(glyph_t) + ((glyph_t *)pointer)->DataSize; | ||||
|     } | ||||
|     else { | ||||
|     else | ||||
|       pointer++; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| @ -86,6 +85,13 @@ void TFT_String::set() { | ||||
| 
 | ||||
| uint8_t read_byte(uint8_t *byte) { return *byte; } | ||||
| 
 | ||||
| /**
 | ||||
|  * Add a string, applying substitutions for the following characters: | ||||
|  * | ||||
|  *   = displays  '0'....'10' for indexes 0 - 10 | ||||
|  *   ~ displays  '1'....'11' for indexes 0 - 10 | ||||
|  *   * displays 'E1'...'E11' for indexes 0 - 10 (By default. Uses LCD_FIRST_TOOL) | ||||
|  */ | ||||
| void TFT_String::add(uint8_t *string, int8_t index, uint8_t *itemString) { | ||||
|   wchar_t wchar; | ||||
| 
 | ||||
|  | ||||
| @ -25,7 +25,6 @@ | ||||
| #if HAS_SPI_FLASH | ||||
| 
 | ||||
| #include "W25Qxx.h" | ||||
| #include <SPI.h> | ||||
| 
 | ||||
| W25QXXFlash W25QXX; | ||||
| 
 | ||||
| @ -41,6 +40,11 @@ W25QXXFlash W25QXX; | ||||
| #ifndef SPI_FLASH_CS_PIN | ||||
|   #define SPI_FLASH_CS_PIN   W25QXX_CS_PIN | ||||
| #endif | ||||
| #ifndef NC | ||||
|   #define NC -1 | ||||
| #endif | ||||
| 
 | ||||
| MarlinSPI W25QXXFlash::mySPI(SPI_FLASH_MOSI_PIN, SPI_FLASH_MISO_PIN, SPI_FLASH_SCK_PIN, NC); | ||||
| 
 | ||||
| #define W25QXX_CS_H OUT_WRITE(SPI_FLASH_CS_PIN, HIGH) | ||||
| #define W25QXX_CS_L OUT_WRITE(SPI_FLASH_CS_PIN, LOW) | ||||
| @ -69,11 +73,11 @@ void W25QXXFlash::init(uint8_t spiRate) { | ||||
|     case SPI_SPEED_6:       clock = SPI_CLOCK_DIV64; break; | ||||
|     default:                clock = SPI_CLOCK_DIV2;// Default from the SPI library
 | ||||
|   } | ||||
|   SPI.setModule(SPI_DEVICE); | ||||
|   SPI.begin(); | ||||
|   SPI.setClockDivider(clock); | ||||
|   SPI.setBitOrder(MSBFIRST); | ||||
|   SPI.setDataMode(SPI_MODE0); | ||||
| 
 | ||||
|   mySPI.setClockDivider(clock); | ||||
|   mySPI.setBitOrder(MSBFIRST); | ||||
|   mySPI.setDataMode(SPI_MODE0); | ||||
|   mySPI.begin(); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| @ -82,12 +86,12 @@ void W25QXXFlash::init(uint8_t spiRate) { | ||||
|  * @return Byte received | ||||
|  */ | ||||
| uint8_t W25QXXFlash::spi_flash_Rec() { | ||||
|   const uint8_t returnByte = SPI.transfer(0xFF); | ||||
|   const uint8_t returnByte = mySPI.transfer(0xFF); | ||||
|   return returnByte; | ||||
| } | ||||
| 
 | ||||
| uint8_t W25QXXFlash::spi_flash_read_write_byte(uint8_t data) { | ||||
|   const uint8_t returnByte = SPI.transfer(data); | ||||
|   const uint8_t returnByte = mySPI.transfer(data); | ||||
|   return returnByte; | ||||
| } | ||||
| 
 | ||||
| @ -100,7 +104,9 @@ uint8_t W25QXXFlash::spi_flash_read_write_byte(uint8_t data) { | ||||
|  * | ||||
|  * @details Uses DMA | ||||
|  */ | ||||
| void W25QXXFlash::spi_flash_Read(uint8_t* buf, uint16_t nbyte) { SPI.dmaTransfer(0, const_cast<uint8_t*>(buf), nbyte); } | ||||
| void W25QXXFlash::spi_flash_Read(uint8_t* buf, uint16_t nbyte) { | ||||
|   mySPI.dmaTransfer(0, const_cast<uint8_t*>(buf), nbyte); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief  Send a single byte on SPI port | ||||
| @ -109,7 +115,7 @@ void W25QXXFlash::spi_flash_Read(uint8_t* buf, uint16_t nbyte) { SPI.dmaTransfer | ||||
|  * | ||||
|  * @details | ||||
|  */ | ||||
| void W25QXXFlash::spi_flash_Send(uint8_t b) { SPI.send(b); } | ||||
| void W25QXXFlash::spi_flash_Send(uint8_t b) { mySPI.transfer(b); } | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief  Write token and then write from 512 byte buffer to SPI (for SD card) | ||||
| @ -120,8 +126,8 @@ void W25QXXFlash::spi_flash_Send(uint8_t b) { SPI.send(b); } | ||||
|  * @details Use DMA | ||||
|  */ | ||||
| void W25QXXFlash::spi_flash_SendBlock(uint8_t token, const uint8_t* buf) { | ||||
|   SPI.send(token); | ||||
|   SPI.dmaSend(const_cast<uint8_t*>(buf), 512); | ||||
|   mySPI.transfer(token); | ||||
|   mySPI.dmaSend(const_cast<uint8_t*>(buf), 512); | ||||
| } | ||||
| 
 | ||||
| uint16_t W25QXXFlash::W25QXX_ReadID(void) { | ||||
|  | ||||
| @ -23,6 +23,8 @@ | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| #include HAL_PATH(../HAL, MarlinSPI.h) | ||||
| 
 | ||||
| #define W25X_WriteEnable        0x06 | ||||
| #define W25X_WriteDisable       0x04 | ||||
| #define W25X_ReadStatusReg      0x05 | ||||
| @ -49,6 +51,8 @@ | ||||
| #define SPI_FLASH_PerWritePageSize   256 | ||||
| 
 | ||||
| class W25QXXFlash { | ||||
| private: | ||||
|   static MarlinSPI mySPI; | ||||
| public: | ||||
|   void init(uint8_t spiRate); | ||||
|   static uint8_t spi_flash_Rec(); | ||||
|  | ||||
| @ -191,6 +191,9 @@ | ||||
|   #define FSMC_DMA_DEV                      DMA2 | ||||
|   #define FSMC_DMA_CHANNEL               DMA_CH5 | ||||
| 
 | ||||
|   #define TFT_CS_PIN                 FSMC_CS_PIN | ||||
|   #define TFT_RS_PIN                 FSMC_RS_PIN | ||||
| 
 | ||||
|   #define TOUCH_BUTTONS_HW_SPI | ||||
|   #define TOUCH_BUTTONS_HW_SPI_DEVICE          2 | ||||
| 
 | ||||
|  | ||||
| @ -15,7 +15,7 @@ opt_set MOTHERBOARD BOARD_MKS_ROBIN_NANO | ||||
| exec_test $1 $2 "MKS Robin nano v1.2 Emulated DOGM FSMC" | ||||
| 
 | ||||
| # | ||||
| # MKS Robin v2 nano LVGL SPI | ||||
| # MKS Robin v2 nano Emulated DOGM SPI | ||||
| # (Robin v2 nano has no FSMC interface) | ||||
| # | ||||
| use_example_configs Mks/Robin | ||||
|  | ||||
							
								
								
									
										69
									
								
								buildroot/tests/mks_robin_nano35_stm32-tests
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								buildroot/tests/mks_robin_nano35_stm32-tests
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,69 @@ | ||||
| #!/usr/bin/env bash | ||||
| # | ||||
| # Build tests for MKS Robin nano | ||||
| # (STM32F1 genericSTM32F103VE) | ||||
| # | ||||
| 
 | ||||
| # exit on first failure | ||||
| set -e | ||||
| 
 | ||||
| # | ||||
| # MKS Robin nano v1.2 Emulated DOGM FSMC | ||||
| # | ||||
| use_example_configs Mks/Robin | ||||
| opt_set MOTHERBOARD BOARD_MKS_ROBIN_NANO | ||||
| exec_test $1 $2 "MKS Robin nano v1.2 Emulated DOGM FSMC" | ||||
| 
 | ||||
| # | ||||
| # MKS Robin v2 nano Emulated DOGM SPI | ||||
| # (Robin v2 nano has no FSMC interface) | ||||
| # | ||||
| use_example_configs Mks/Robin | ||||
| opt_set MOTHERBOARD BOARD_MKS_ROBIN_NANO_V2 | ||||
| opt_disable TFT_INTERFACE_FSMC | ||||
| opt_enable TFT_INTERFACE_SPI | ||||
| exec_test $1 $2 "MKS Robin v2 nano Emulated DOGM SPI" | ||||
| 
 | ||||
| # | ||||
| # MKS Robin nano v1.2 LVGL FSMC | ||||
| # | ||||
| # use_example_configs Mks/Robin | ||||
| # opt_set MOTHERBOARD BOARD_MKS_ROBIN_NANO | ||||
| # opt_disable TFT_CLASSIC_UI TFT_COLOR_UI TOUCH_SCREEN TFT_RES_320x240 | ||||
| # opt_enable TFT_LVGL_UI TFT_RES_480x320 | ||||
| # exec_test $1 $2 "MKS Robin nano v1.2 LVGL FSMC" | ||||
| 
 | ||||
| # | ||||
| # MKS Robin v2 nano LVGL SPI | ||||
| # (Robin v2 nano has no FSMC interface) | ||||
| # | ||||
| # use_example_configs Mks/Robin | ||||
| # opt_set MOTHERBOARD BOARD_MKS_ROBIN_NANO_V2 | ||||
| # opt_disable TFT_INTERFACE_FSMC TFT_COLOR_UI TOUCH_SCREEN TFT_RES_320x240 | ||||
| # opt_enable TFT_INTERFACE_SPI TFT_LVGL_UI TFT_RES_480x320 | ||||
| # exec_test $1 $2 "MKS Robin v2 nano LVGL SPI" | ||||
| 
 | ||||
| # | ||||
| # MKS Robin v2 nano New Color UI 480x320 SPI | ||||
| # (Robin v2 nano has no FSMC interface) | ||||
| # | ||||
| use_example_configs Mks/Robin | ||||
| opt_set MOTHERBOARD BOARD_MKS_ROBIN_NANO_V2 | ||||
| opt_disable TFT_INTERFACE_FSMC TFT_RES_320x240 | ||||
| opt_enable TFT_INTERFACE_SPI TFT_RES_480x320 | ||||
| exec_test $1 $2 "MKS Robin v2 nano New Color UI 480x320 SPI" | ||||
| 
 | ||||
| # | ||||
| # MKS Robin v2 nano LVGL SPI + TMC | ||||
| # (Robin v2 nano has no FSMC interface) | ||||
| # | ||||
| # use_example_configs Mks/Robin | ||||
| # opt_set MOTHERBOARD BOARD_MKS_ROBIN_NANO_V2 | ||||
| # opt_disable TFT_INTERFACE_FSMC TFT_COLOR_UI TOUCH_SCREEN TFT_RES_320x240 | ||||
| # opt_enable TFT_INTERFACE_SPI TFT_LVGL_UI TFT_RES_480x320 | ||||
| # opt_set X_DRIVER_TYPE TMC2209 | ||||
| # opt_set Y_DRIVER_TYPE TMC2209 | ||||
| # exec_test $1 $2 "MKS Robin v2 nano LVGL SPI + TMC" | ||||
| 
 | ||||
| # cleanup | ||||
| restore_configs | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user