stm: SPI: revamp pin search code
I discussed with Hierophect on Discord about how to "de-nest" the code for configuring SPI objects on STM, because the problems with one nesting level per pin becomes unmanageable with the up to 10 pins of SDIO. This code (which is only compile-tested so far) demonstrates the concept we discussed. The SCK pin is always required. Loop over all possibilities of the SCK pin. When we are considering a particular item in the mcu_spi_sck_list we have now become committed to using a particular periph_index. If all the other pins can be satisfied by that periph_index, then we have a working combination. Once we have a working combination that is not reserved, we can return that combination. On reaching the end, we have checked all the possible possibilities and can give the same errors as before: One if there was a possibility that worked but was reserved; and another if no possibility worked.
This commit is contained in:
parent
9b4b655b03
commit
57ab4f1329
|
@ -107,105 +107,79 @@ void spi_reset(void) {
|
|||
spi_clock_disable(ALL_CLOCKS & ~(never_reset_mask));
|
||||
}
|
||||
|
||||
void common_hal_busio_spi_construct(busio_spi_obj_t *self,
|
||||
STATIC const mcu_periph_obj_t *find_pin_function(const mcu_periph_obj_t *table, size_t sz, const mcu_pin_obj_t *pin, int periph_index) {
|
||||
for(size_t i = 0; i<sz; i++, table++) {
|
||||
if(periph_index == table->periph_index && pin == table->pin ) {
|
||||
return table;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//match pins to SPI objects
|
||||
STATIC int check_pins(busio_spi_obj_t *self,
|
||||
const mcu_pin_obj_t * sck, const mcu_pin_obj_t * mosi,
|
||||
const mcu_pin_obj_t * miso) {
|
||||
|
||||
//match pins to SPI objects
|
||||
SPI_TypeDef * SPIx;
|
||||
bool spi_taken = false;
|
||||
|
||||
uint8_t sck_len = MP_ARRAY_SIZE(mcu_spi_sck_list);
|
||||
uint8_t mosi_len = MP_ARRAY_SIZE(mcu_spi_mosi_list);
|
||||
uint8_t miso_len = MP_ARRAY_SIZE(mcu_spi_miso_list);
|
||||
bool spi_taken = false;
|
||||
|
||||
//SCK is not optional. MOSI and MISO are
|
||||
for (uint i = 0; i < sck_len; i++) {
|
||||
if (mcu_spi_sck_list[i].pin == sck) {
|
||||
//if both MOSI and MISO exist, loop search normally
|
||||
if ((mosi != NULL) && (miso != NULL)) {
|
||||
//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].periph_index == mcu_spi_mosi_list[j].periph_index)
|
||||
&& (mcu_spi_sck_list[i].periph_index == mcu_spi_miso_list[k].periph_index)) {
|
||||
//keep looking if the SPI is taken, edge case
|
||||
if (reserved_spi[mcu_spi_sck_list[i].periph_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;
|
||||
}
|
||||
}
|
||||
if (self->sck != NULL) {
|
||||
break; // Multi-level break to pick lowest peripheral
|
||||
}
|
||||
}
|
||||
}
|
||||
if (self->sck != NULL) {
|
||||
break;
|
||||
}
|
||||
// if just MISO, reduce search
|
||||
} else if (miso != NULL) {
|
||||
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].periph_index == mcu_spi_miso_list[j].periph_index)) {
|
||||
if (reserved_spi[mcu_spi_sck_list[i].periph_index - 1]) {
|
||||
spi_taken = true;
|
||||
continue;
|
||||
}
|
||||
self->sck = &mcu_spi_sck_list[i];
|
||||
self->mosi = NULL;
|
||||
self->miso = &mcu_spi_miso_list[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (self->sck != NULL) {
|
||||
break;
|
||||
}
|
||||
// if just MOSI, reduce search
|
||||
} else if (mosi != NULL) {
|
||||
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].periph_index == mcu_spi_mosi_list[j].periph_index)) {
|
||||
if (reserved_spi[mcu_spi_sck_list[i].periph_index - 1]) {
|
||||
spi_taken = true;
|
||||
continue;
|
||||
}
|
||||
self->sck = &mcu_spi_sck_list[i];
|
||||
self->mosi = &mcu_spi_mosi_list[j];
|
||||
self->miso = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (self->sck != NULL) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
//throw an error immediately
|
||||
mp_raise_ValueError(translate("Must provide MISO or MOSI pin"));
|
||||
}
|
||||
}
|
||||
if (!sck) {
|
||||
mp_raise_ValueError(translate("Must provide SCK pin"));
|
||||
}
|
||||
|
||||
//handle typedef selection, errors
|
||||
if (self->sck != NULL && (self->mosi != NULL || self->miso != NULL)) {
|
||||
SPIx = mcu_spi_banks[self->sck->periph_index - 1];
|
||||
} else {
|
||||
if (spi_taken) {
|
||||
mp_raise_ValueError(translate("Hardware busy, try alternative pins"));
|
||||
} else {
|
||||
mp_raise_ValueError(translate("Invalid SPI pin selection"));
|
||||
}
|
||||
if (!miso && !mosi) {
|
||||
mp_raise_ValueError(translate("Must provide MISO or MOSI pin"));
|
||||
}
|
||||
|
||||
// Loop over each possibility for SCK. Check whether MISO and/or MOSI can be used on the same peripheral
|
||||
for (uint i = 0; i < sck_len; i++) {
|
||||
const mcu_periph_obj_t *mcu_spi_sck = &mcu_spi_sck_list[i];
|
||||
if (mcu_spi_sck->pin != sck) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int periph_index = mcu_spi_sck->periph_index;
|
||||
|
||||
const mcu_periph_obj_t *mcu_spi_miso = NULL;
|
||||
if (miso && !(mcu_spi_miso = find_pin_function(mcu_spi_miso_list, miso_len, miso, periph_index))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const mcu_periph_obj_t *mcu_spi_mosi = NULL;
|
||||
if (mosi && !(mcu_spi_mosi = find_pin_function(mcu_spi_mosi_list, mosi_len, mosi, periph_index))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (reserved_spi[periph_index-1]) {
|
||||
spi_taken = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
self->sck = mcu_spi_sck;
|
||||
self->mosi = mcu_spi_mosi;
|
||||
self->miso = mcu_spi_miso;
|
||||
|
||||
return periph_index;
|
||||
}
|
||||
|
||||
if (spi_taken) {
|
||||
mp_raise_ValueError(translate("Hardware busy, try alternative pins"));
|
||||
} else {
|
||||
mp_raise_ValueError(translate("Invalid SPI pin selection"));
|
||||
}
|
||||
}
|
||||
|
||||
void common_hal_busio_spi_construct(busio_spi_obj_t *self,
|
||||
const mcu_pin_obj_t * sck, const mcu_pin_obj_t * mosi,
|
||||
const mcu_pin_obj_t * miso) {
|
||||
|
||||
int periph_index = check_pins(self, sck, mosi, miso);
|
||||
SPI_TypeDef * SPIx = mcu_spi_banks[periph_index - 1];
|
||||
|
||||
//Start GPIO for each pin
|
||||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
GPIO_InitStruct.Pin = pin_mask(sck->number);
|
||||
|
|
Loading…
Reference in New Issue