3636#include "supervisor/shared/translate.h"
3737#include "common-hal/microcontroller/Pin.h"
3838
39+ // Note that any bugs introduced in this file can cause crashes at startup
40+ // for chips using external SPI flash.
41+
3942#define MAX_SPI 6 //TODO; replace this as part of periph cleanup
4043#define ALL_CLOCKS 0xFF
4144
@@ -49,10 +52,10 @@ STATIC void spi_clock_disable(uint8_t mask);
4952STATIC uint32_t get_busclock (SPI_TypeDef * instance ) {
5053 //SPI2 and 3 are on PCLK1, if they exist.
5154 #ifdef SPI2
52- if (instance == SPI2 ) return HAL_RCC_GetPCLK1Freq ();
55+ if (instance == SPI2 ) return HAL_RCC_GetPCLK1Freq ();
5356 #endif
5457 #ifdef SPI3
55- if (instance == SPI3 ) return HAL_RCC_GetPCLK1Freq ();
58+ if (instance == SPI3 ) return HAL_RCC_GetPCLK1Freq ();
5659 #endif
5760 return HAL_RCC_GetPCLK2Freq ();
5861}
@@ -79,38 +82,80 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
7982 uint8_t sck_len = sizeof (mcu_spi_sck_list )/sizeof (* mcu_spi_sck_list );
8083 uint8_t mosi_len = sizeof (mcu_spi_mosi_list )/sizeof (* mcu_spi_mosi_list );
8184 uint8_t miso_len = sizeof (mcu_spi_miso_list )/sizeof (* mcu_spi_miso_list );
82-
8385 bool spi_taken = false;
84- //sck
85- for (uint i = 0 ; i < sck_len ;i ++ ) {
86+
87+ //SCK is not optional. MOSI and MISO are
88+ for (uint i = 0 ; i < sck_len ;i ++ ) {
8689 if (mcu_spi_sck_list [i ].pin == sck ) {
87- //mosi
88- for (uint j = 0 ; j < mosi_len ;j ++ ) {
89- if (mcu_spi_mosi_list [j ].pin == mosi ) {
90- //miso
91- for (uint k = 0 ; k < miso_len ;k ++ ) {
92- if ((mcu_spi_miso_list [k ].pin == miso ) //everything needs the same index
93- && (mcu_spi_sck_list [i ].spi_index == mcu_spi_mosi_list [j ].spi_index )
94- && (mcu_spi_sck_list [i ].spi_index == mcu_spi_miso_list [k ].spi_index )) {
95- //keep looking if the SPI is taken, edge case
96- if (reserved_spi [mcu_spi_sck_list [i ].spi_index - 1 ]) {
97- spi_taken = true;
98- continue ;
90+ //if both MOSI and MISO exist, loop search normally
91+ if ((mosi != mp_const_none ) && (miso != mp_const_none )) {
92+ //MOSI
93+ for (uint j = 0 ; j < mosi_len ;j ++ ) {
94+ if (mcu_spi_mosi_list [j ].pin == mosi ) {
95+ //MISO
96+ for (uint k = 0 ; k < miso_len ;k ++ ) {
97+ if ((mcu_spi_miso_list [k ].pin == miso ) //everything needs the same index
98+ && (mcu_spi_sck_list [i ].spi_index == mcu_spi_mosi_list [j ].spi_index )
99+ && (mcu_spi_sck_list [i ].spi_index == mcu_spi_miso_list [k ].spi_index )) {
100+ //keep looking if the SPI is taken, edge case
101+ if (reserved_spi [mcu_spi_sck_list [i ].spi_index - 1 ]) {
102+ spi_taken = true;
103+ continue ;
104+ }
105+ //store pins if not
106+ self -> sck = & mcu_spi_sck_list [i ];
107+ self -> mosi = & mcu_spi_mosi_list [j ];
108+ self -> miso = & mcu_spi_miso_list [k ];
109+ break ;
99110 }
100- //store pins if not
101- self -> sck = & mcu_spi_sck_list [i ];
102- self -> mosi = & mcu_spi_mosi_list [j ];
103- self -> miso = & mcu_spi_miso_list [k ];
104- break ;
105- }
106- }
111+ }
112+ }
107113 }
114+ // if just MISO, reduce search
115+ } else if (miso != mp_const_none ) {
116+ for (uint j = 0 ; j < miso_len ;j ++ ) {
117+ if ((mcu_spi_miso_list [j ].pin == miso ) //only SCK and MISO need the same index
118+ && (mcu_spi_sck_list [i ].spi_index == mcu_spi_miso_list [j ].spi_index )) {
119+ //keep looking if the SPI is taken, edge case
120+ if (reserved_spi [mcu_spi_sck_list [i ].spi_index - 1 ]) {
121+ spi_taken = true;
122+ continue ;
123+ }
124+ //store pins if not
125+ self -> sck = & mcu_spi_sck_list [i ];
126+ self -> mosi = NULL ;
127+ self -> miso = & mcu_spi_miso_list [j ];
128+ break ;
129+ }
130+ }
131+ // if just MOSI, reduce search
132+ } else if (mosi != mp_const_none ) {
133+ for (uint j = 0 ; j < mosi_len ;j ++ ) {
134+ if ((mcu_spi_mosi_list [j ].pin == mosi ) //only SCK and MOSI need the same index
135+ && (mcu_spi_sck_list [i ].spi_index == mcu_spi_mosi_list [j ].spi_index )) {
136+ //keep looking if the SPI is taken, edge case
137+ if (reserved_spi [mcu_spi_sck_list [i ].spi_index - 1 ]) {
138+ spi_taken = true;
139+ continue ;
140+ }
141+ //store pins if not
142+ self -> sck = & mcu_spi_sck_list [i ];
143+ self -> mosi = & mcu_spi_mosi_list [j ];
144+ self -> miso = NULL ;
145+ break ;
146+ }
147+ }
148+ } else {
149+ //throw an error immediately
150+ mp_raise_ValueError (translate ("Must provide MISO or MOSI pin" ));
108151 }
109152 }
110153 }
111154
112155 //handle typedef selection, errors
113- if (self -> sck != NULL && self -> mosi != NULL && self -> miso != NULL ) {
156+ if ( (self -> sck != NULL && self -> mosi != NULL && self -> miso != NULL ) ||
157+ (self -> sck != NULL && self -> mosi != NULL && miso == mp_const_none ) ||
158+ (self -> sck != NULL && self -> miso != NULL && mosi == mp_const_none )) {
114159 SPIx = mcu_spi_banks [self -> sck -> spi_index - 1 ];
115160 } else {
116161 if (spi_taken ) {
@@ -129,26 +174,31 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
129174 GPIO_InitStruct .Alternate = self -> sck -> altfn_index ;
130175 HAL_GPIO_Init (pin_port (sck -> port ), & GPIO_InitStruct );
131176
132- GPIO_InitStruct .Pin = pin_mask (mosi -> number );
133- GPIO_InitStruct .Mode = GPIO_MODE_AF_PP ;
134- GPIO_InitStruct .Pull = GPIO_NOPULL ;
135- GPIO_InitStruct .Speed = GPIO_SPEED_FREQ_VERY_HIGH ;
136- GPIO_InitStruct .Alternate = self -> mosi -> altfn_index ;
137- HAL_GPIO_Init (pin_port (mosi -> port ), & GPIO_InitStruct );
177+ if (self -> mosi != NULL ) {
178+ GPIO_InitStruct .Pin = pin_mask (mosi -> number );
179+ GPIO_InitStruct .Mode = GPIO_MODE_AF_PP ;
180+ GPIO_InitStruct .Pull = GPIO_NOPULL ;
181+ GPIO_InitStruct .Speed = GPIO_SPEED_FREQ_VERY_HIGH ;
182+ GPIO_InitStruct .Alternate = self -> mosi -> altfn_index ;
183+ HAL_GPIO_Init (pin_port (mosi -> port ), & GPIO_InitStruct );
184+ }
138185
139- GPIO_InitStruct .Pin = pin_mask (miso -> number );
140- GPIO_InitStruct .Mode = GPIO_MODE_AF_PP ;
141- GPIO_InitStruct .Pull = GPIO_NOPULL ;
142- GPIO_InitStruct .Speed = GPIO_SPEED_FREQ_VERY_HIGH ;
143- GPIO_InitStruct .Alternate = self -> miso -> altfn_index ;
144- HAL_GPIO_Init (pin_port (miso -> port ), & GPIO_InitStruct );
186+ if (self -> miso != NULL ) {
187+ GPIO_InitStruct .Pin = pin_mask (miso -> number );
188+ GPIO_InitStruct .Mode = GPIO_MODE_AF_PP ;
189+ GPIO_InitStruct .Pull = GPIO_NOPULL ;
190+ GPIO_InitStruct .Speed = GPIO_SPEED_FREQ_VERY_HIGH ;
191+ GPIO_InitStruct .Alternate = self -> miso -> altfn_index ;
192+ HAL_GPIO_Init (pin_port (miso -> port ), & GPIO_InitStruct );
193+ }
145194
146195 spi_clock_enable (1 <<(self -> sck -> spi_index - 1 ));
147196 reserved_spi [self -> sck -> spi_index - 1 ] = true;
148197
149198 self -> handle .Instance = SPIx ;
150199 self -> handle .Init .Mode = SPI_MODE_MASTER ;
151- self -> handle .Init .Direction = SPI_DIRECTION_2LINES ;
200+ // Direction change only required for RX-only, see RefMan RM0090:884
201+ self -> handle .Init .Direction = (self -> mosi == NULL ) ? SPI_CR1_RXONLY : SPI_DIRECTION_2LINES ;
152202 self -> handle .Init .DataSize = SPI_DATASIZE_8BIT ;
153203 self -> handle .Init .CLKPolarity = SPI_POLARITY_LOW ;
154204 self -> handle .Init .CLKPhase = SPI_PHASE_1EDGE ;
@@ -169,17 +219,25 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
169219 self -> bits = 8 ;
170220
171221 claim_pin (sck );
172- claim_pin (mosi );
173- claim_pin (miso );
222+ if (self -> mosi != NULL ) {
223+ claim_pin (mosi );
224+ }
225+ if (self -> miso != NULL ) {
226+ claim_pin (miso );
227+ }
174228}
175229
176230void common_hal_busio_spi_never_reset (busio_spi_obj_t * self ) {
177- for (size_t i = 0 ; i < MP_ARRAY_SIZE (mcu_spi_banks ); i ++ ) {
231+ for (size_t i = 0 ; i < MP_ARRAY_SIZE (mcu_spi_banks ); i ++ ) {
178232 if (mcu_spi_banks [i ] == self -> handle .Instance ) {
179233 never_reset_spi [i ] = true;
180234 never_reset_pin_number (self -> sck -> pin -> port , self -> sck -> pin -> number );
181- never_reset_pin_number (self -> mosi -> pin -> port , self -> mosi -> pin -> number );
182- never_reset_pin_number (self -> miso -> pin -> port , self -> miso -> pin -> number );
235+ if (self -> mosi != NULL ) {
236+ never_reset_pin_number (self -> mosi -> pin -> port , self -> mosi -> pin -> number );
237+ }
238+ if (self -> miso != NULL ) {
239+ never_reset_pin_number (self -> miso -> pin -> port , self -> miso -> pin -> number );
240+ }
183241 break ;
184242 }
185243 }
@@ -195,8 +253,12 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) {
195253 never_reset_spi [self -> sck -> spi_index - 1 ] = false;
196254
197255 reset_pin_number (self -> sck -> pin -> port ,self -> sck -> pin -> number );
198- reset_pin_number (self -> mosi -> pin -> port ,self -> mosi -> pin -> number );
199- reset_pin_number (self -> miso -> pin -> port ,self -> miso -> pin -> number );
256+ if (self -> mosi != NULL ) {
257+ reset_pin_number (self -> mosi -> pin -> port ,self -> mosi -> pin -> number );
258+ }
259+ if (self -> miso != NULL ) {
260+ reset_pin_number (self -> miso -> pin -> port ,self -> miso -> pin -> number );
261+ }
200262 self -> sck = mp_const_none ;
201263 self -> mosi = mp_const_none ;
202264 self -> miso = mp_const_none ;
@@ -232,7 +294,9 @@ bool common_hal_busio_spi_configure(busio_spi_obj_t *self,
232294 uint32_t baudrate , uint8_t polarity , uint8_t phase , uint8_t bits ) {
233295 //This resets the SPI, so check before updating it redundantly
234296 if (baudrate == self -> baudrate && polarity == self -> polarity
235- && phase == self -> phase && bits == self -> bits ) return true;
297+ && phase == self -> phase && bits == self -> bits ) {
298+ return true;
299+ }
236300
237301 //Deinit SPI
238302 HAL_SPI_DeInit (& self -> handle );
@@ -243,13 +307,6 @@ bool common_hal_busio_spi_configure(busio_spi_obj_t *self,
243307
244308 self -> handle .Init .BaudRatePrescaler = stm32_baud_to_spi_div (baudrate , & self -> prescaler ,
245309 get_busclock (self -> handle .Instance ));
246- self -> handle .Init .Mode = SPI_MODE_MASTER ;
247- self -> handle .Init .Direction = SPI_DIRECTION_2LINES ;
248- self -> handle .Init .NSS = SPI_NSS_SOFT ;
249- self -> handle .Init .FirstBit = SPI_FIRSTBIT_MSB ;
250- self -> handle .Init .TIMode = SPI_TIMODE_DISABLE ;
251- self -> handle .Init .CRCCalculation = SPI_CRCCALCULATION_DISABLE ;
252- self -> handle .Init .CRCPolynomial = 10 ;
253310
254311 if (HAL_SPI_Init (& self -> handle ) != HAL_OK )
255312 {
@@ -292,18 +349,27 @@ void common_hal_busio_spi_unlock(busio_spi_obj_t *self) {
292349
293350bool common_hal_busio_spi_write (busio_spi_obj_t * self ,
294351 const uint8_t * data , size_t len ) {
352+ if (self -> mosi == NULL ) {
353+ mp_raise_ValueError (translate ("No MOSI Pin" ));
354+ }
295355 HAL_StatusTypeDef result = HAL_SPI_Transmit (& self -> handle , (uint8_t * )data , (uint16_t )len , HAL_MAX_DELAY );
296356 return result == HAL_OK ;
297357}
298358
299359bool common_hal_busio_spi_read (busio_spi_obj_t * self ,
300360 uint8_t * data , size_t len , uint8_t write_value ) {
361+ if (self -> miso == NULL ) {
362+ mp_raise_ValueError (translate ("No MISO Pin" ));
363+ }
301364 HAL_StatusTypeDef result = HAL_SPI_Receive (& self -> handle , data , (uint16_t )len , HAL_MAX_DELAY );
302365 return result == HAL_OK ;
303366}
304367
305368bool common_hal_busio_spi_transfer (busio_spi_obj_t * self ,
306369 uint8_t * data_out , uint8_t * data_in , size_t len ) {
370+ if (self -> miso == NULL || self -> mosi == NULL ) {
371+ mp_raise_ValueError (translate ("Missing MISO or MOSI Pin" ));
372+ }
307373 HAL_StatusTypeDef result = HAL_SPI_TransmitReceive (& self -> handle ,
308374 data_out , data_in , (uint16_t )len ,HAL_MAX_DELAY );
309375 return result == HAL_OK ;
0 commit comments