Skip to content

STM32: Allow simplex SPI #2459

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 9, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 119 additions & 53 deletions ports/stm32f4/common-hal/busio/SPI.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@
#include "supervisor/shared/translate.h"
#include "common-hal/microcontroller/Pin.h"

// Note that any bugs introduced in this file can cause crashes at startup
// for chips using external SPI flash.

#define MAX_SPI 6 //TODO; replace this as part of periph cleanup
#define ALL_CLOCKS 0xFF

Expand All @@ -49,10 +52,10 @@ STATIC void spi_clock_disable(uint8_t mask);
STATIC uint32_t get_busclock(SPI_TypeDef * instance) {
//SPI2 and 3 are on PCLK1, if they exist.
#ifdef SPI2
if(instance == SPI2) return HAL_RCC_GetPCLK1Freq();
if (instance == SPI2) return HAL_RCC_GetPCLK1Freq();
#endif
#ifdef SPI3
if(instance == SPI3) return HAL_RCC_GetPCLK1Freq();
if (instance == SPI3) return HAL_RCC_GetPCLK1Freq();
#endif
return HAL_RCC_GetPCLK2Freq();
}
Expand All @@ -79,38 +82,80 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
uint8_t sck_len = sizeof(mcu_spi_sck_list)/sizeof(*mcu_spi_sck_list);
uint8_t mosi_len = sizeof(mcu_spi_mosi_list)/sizeof(*mcu_spi_mosi_list);
uint8_t miso_len = sizeof(mcu_spi_miso_list)/sizeof(*mcu_spi_miso_list);

bool spi_taken = false;
//sck
for(uint i=0; i<sck_len;i++) {

//SCK is not optional. MOSI and MISO are
for (uint i=0; i<sck_len;i++) {
if (mcu_spi_sck_list[i].pin == sck) {
//mosi
for(uint j=0; j<mosi_len;j++) {
if (mcu_spi_mosi_list[j].pin == mosi) {
//miso
for(uint k=0; k<miso_len;k++) {
if ((mcu_spi_miso_list[k].pin == miso) //everything needs the same index
&& (mcu_spi_sck_list[i].spi_index == mcu_spi_mosi_list[j].spi_index)
&& (mcu_spi_sck_list[i].spi_index == mcu_spi_miso_list[k].spi_index)) {
//keep looking if the SPI is taken, edge case
if(reserved_spi[mcu_spi_sck_list[i].spi_index-1]) {
spi_taken = true;
continue;
//if both MOSI and MISO exist, loop search normally
if ((mosi != mp_const_none) && (miso != mp_const_none)) {
//MOSI
for (uint j=0; j<mosi_len;j++) {
if (mcu_spi_mosi_list[j].pin == mosi) {
//MISO
for (uint k=0; k<miso_len;k++) {
if ((mcu_spi_miso_list[k].pin == miso) //everything needs the same index
&& (mcu_spi_sck_list[i].spi_index == mcu_spi_mosi_list[j].spi_index)
&& (mcu_spi_sck_list[i].spi_index == mcu_spi_miso_list[k].spi_index)) {
//keep looking if the SPI is taken, edge case
if (reserved_spi[mcu_spi_sck_list[i].spi_index-1]) {
spi_taken = true;
continue;
}
//store pins if not
self->sck = &mcu_spi_sck_list[i];
self->mosi = &mcu_spi_mosi_list[j];
self->miso = &mcu_spi_miso_list[k];
break;
}
//store pins if not
self->sck = &mcu_spi_sck_list[i];
self->mosi = &mcu_spi_mosi_list[j];
self->miso = &mcu_spi_miso_list[k];
break;
}
}
}
}
}
// if just MISO, reduce search
} else if (miso != mp_const_none) {
for (uint j=0; j<miso_len;j++) {
if ((mcu_spi_miso_list[j].pin == miso) //only SCK and MISO need the same index
&& (mcu_spi_sck_list[i].spi_index == mcu_spi_miso_list[j].spi_index)) {
//keep looking if the SPI is taken, edge case
if (reserved_spi[mcu_spi_sck_list[i].spi_index-1]) {
spi_taken = true;
continue;
}
//store pins if not
self->sck = &mcu_spi_sck_list[i];
self->mosi = NULL;
self->miso = &mcu_spi_miso_list[j];
break;
}
}
// if just MOSI, reduce search
} else if (mosi != mp_const_none) {
for (uint j=0; j<mosi_len;j++) {
if ((mcu_spi_mosi_list[j].pin == mosi) //only SCK and MOSI need the same index
&& (mcu_spi_sck_list[i].spi_index == mcu_spi_mosi_list[j].spi_index)) {
//keep looking if the SPI is taken, edge case
if (reserved_spi[mcu_spi_sck_list[i].spi_index-1]) {
spi_taken = true;
continue;
}
//store pins if not
self->sck = &mcu_spi_sck_list[i];
self->mosi = &mcu_spi_mosi_list[j];
self->miso = NULL;
break;
}
}
} else {
//throw an error immediately
mp_raise_ValueError(translate("Must provide MISO or MOSI pin"));
}
}
}

//handle typedef selection, errors
if(self->sck!=NULL && self->mosi!=NULL && self->miso!=NULL ) {
if ( (self->sck!=NULL && self->mosi!=NULL && self->miso != NULL) ||
(self->sck!=NULL && self->mosi!=NULL && miso == mp_const_none) ||
(self->sck!=NULL && self->miso!=NULL && mosi == mp_const_none)) {
SPIx = mcu_spi_banks[self->sck->spi_index-1];
} else {
if (spi_taken) {
Expand All @@ -129,26 +174,31 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
GPIO_InitStruct.Alternate = self->sck->altfn_index;
HAL_GPIO_Init(pin_port(sck->port), &GPIO_InitStruct);

GPIO_InitStruct.Pin = pin_mask(mosi->number);
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = self->mosi->altfn_index;
HAL_GPIO_Init(pin_port(mosi->port), &GPIO_InitStruct);
if (self->mosi != NULL) {
GPIO_InitStruct.Pin = pin_mask(mosi->number);
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = self->mosi->altfn_index;
HAL_GPIO_Init(pin_port(mosi->port), &GPIO_InitStruct);
}

GPIO_InitStruct.Pin = pin_mask(miso->number);
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = self->miso->altfn_index;
HAL_GPIO_Init(pin_port(miso->port), &GPIO_InitStruct);
if (self->miso != NULL) {
GPIO_InitStruct.Pin = pin_mask(miso->number);
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = self->miso->altfn_index;
HAL_GPIO_Init(pin_port(miso->port), &GPIO_InitStruct);
}

spi_clock_enable(1<<(self->sck->spi_index - 1));
reserved_spi[self->sck->spi_index - 1] = true;

self->handle.Instance = SPIx;
self->handle.Init.Mode = SPI_MODE_MASTER;
self->handle.Init.Direction = SPI_DIRECTION_2LINES;
// Direction change only required for RX-only, see RefMan RM0090:884
self->handle.Init.Direction = (self->mosi == NULL) ? SPI_CR1_RXONLY : SPI_DIRECTION_2LINES;
self->handle.Init.DataSize = SPI_DATASIZE_8BIT;
self->handle.Init.CLKPolarity = SPI_POLARITY_LOW;
self->handle.Init.CLKPhase = SPI_PHASE_1EDGE;
Expand All @@ -169,17 +219,25 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
self->bits = 8;

claim_pin(sck);
claim_pin(mosi);
claim_pin(miso);
if (self->mosi != NULL) {
claim_pin(mosi);
}
if (self->miso != NULL) {
claim_pin(miso);
}
}

void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) {
for(size_t i = 0 ; i < MP_ARRAY_SIZE(mcu_spi_banks); i++) {
for (size_t i = 0 ; i < MP_ARRAY_SIZE(mcu_spi_banks); i++) {
if (mcu_spi_banks[i] == self->handle.Instance) {
never_reset_spi[i] = true;
never_reset_pin_number(self->sck->pin->port, self->sck->pin->number);
never_reset_pin_number(self->mosi->pin->port, self->mosi->pin->number);
never_reset_pin_number(self->miso->pin->port, self->miso->pin->number);
if (self->mosi != NULL) {
never_reset_pin_number(self->mosi->pin->port, self->mosi->pin->number);
}
if (self->miso != NULL) {
never_reset_pin_number(self->miso->pin->port, self->miso->pin->number);
}
break;
}
}
Expand All @@ -195,8 +253,12 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) {
never_reset_spi[self->sck->spi_index - 1] = false;

reset_pin_number(self->sck->pin->port,self->sck->pin->number);
reset_pin_number(self->mosi->pin->port,self->mosi->pin->number);
reset_pin_number(self->miso->pin->port,self->miso->pin->number);
if (self->mosi != NULL) {
reset_pin_number(self->mosi->pin->port,self->mosi->pin->number);
}
if (self->miso != NULL) {
reset_pin_number(self->miso->pin->port,self->miso->pin->number);
}
self->sck = mp_const_none;
self->mosi = mp_const_none;
self->miso = mp_const_none;
Expand Down Expand Up @@ -232,7 +294,9 @@ bool common_hal_busio_spi_configure(busio_spi_obj_t *self,
uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) {
//This resets the SPI, so check before updating it redundantly
if (baudrate == self->baudrate && polarity== self->polarity
&& phase == self->phase && bits == self->bits) return true;
&& phase == self->phase && bits == self->bits) {
return true;
}

//Deinit SPI
HAL_SPI_DeInit(&self->handle);
Expand All @@ -243,13 +307,6 @@ bool common_hal_busio_spi_configure(busio_spi_obj_t *self,

self->handle.Init.BaudRatePrescaler = stm32_baud_to_spi_div(baudrate, &self->prescaler,
get_busclock(self->handle.Instance));
self->handle.Init.Mode = SPI_MODE_MASTER;
self->handle.Init.Direction = SPI_DIRECTION_2LINES;
self->handle.Init.NSS = SPI_NSS_SOFT;
self->handle.Init.FirstBit = SPI_FIRSTBIT_MSB;
self->handle.Init.TIMode = SPI_TIMODE_DISABLE;
self->handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
self->handle.Init.CRCPolynomial = 10;

if (HAL_SPI_Init(&self->handle) != HAL_OK)
{
Expand Down Expand Up @@ -292,18 +349,27 @@ void common_hal_busio_spi_unlock(busio_spi_obj_t *self) {

bool common_hal_busio_spi_write(busio_spi_obj_t *self,
const uint8_t *data, size_t len) {
if (self->mosi == NULL) {
mp_raise_ValueError(translate("No MOSI Pin"));
}
HAL_StatusTypeDef result = HAL_SPI_Transmit (&self->handle, (uint8_t *)data, (uint16_t)len, HAL_MAX_DELAY);
return result == HAL_OK;
}

bool common_hal_busio_spi_read(busio_spi_obj_t *self,
uint8_t *data, size_t len, uint8_t write_value) {
if (self->miso == NULL) {
mp_raise_ValueError(translate("No MISO Pin"));
}
HAL_StatusTypeDef result = HAL_SPI_Receive (&self->handle, data, (uint16_t)len, HAL_MAX_DELAY);
return result == HAL_OK;
}

bool common_hal_busio_spi_transfer(busio_spi_obj_t *self,
uint8_t *data_out, uint8_t *data_in, size_t len) {
if (self->miso == NULL || self->mosi == NULL) {
mp_raise_ValueError(translate("Missing MISO or MOSI Pin"));
}
HAL_StatusTypeDef result = HAL_SPI_TransmitReceive (&self->handle,
data_out, data_in, (uint16_t)len,HAL_MAX_DELAY);
return result == HAL_OK;
Expand Down
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy