Skip to content

GIGA: after merging previous changes: SPI1.transfer hangs board #64

Closed
@KurtE

Description

@KurtE

After this last batch of Pull Requests, several of my sketches failed to run. They would hang or look like a reboot
when SPI1.tranfer was called. SPI worked but SPI1 did not.

Most of the time I was using a real simple sketch to debug

#define SPIX SPI1
#include <SPI.h>
#define CS_PIN 10
void setup() {
    Serial.begin(115200);
    while (!Serial && millis() < 5000) {}
    pinMode(CS_PIN, OUTPUT);
    digitalWrite(CS_PIN, HIGH);

    SPIX.begin();
    SPIX.beginTransaction(SPISettings(3000000, MSBFIRST, SPI_MODE0));
    pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
    digitalWrite(CS_PIN, LOW);
    digitalWrite(LED_BUILTIN, HIGH);
    for (uint8_t i = 'a'; i <= 'f'; i++) SPIX.transfer(i);
    digitalWrite(LED_BUILTIN, LOW);
    digitalWrite(CS_PIN, HIGH);
    delay(50);
    Serial.println("Paused");
    while (Serial.read() == -1) {}
    while (Serial.read() != -1) {}
}

I am not sure if anyone would want to see all of the debug stuff I put into the zephyr spi code:

spi_ll_stm32.zip
But included it just in case.

We found that it hung in the function:

/* Shift a SPI frame as master. */
static void spi_stm32_shift_m(const struct spi_stm32_config *cfg,
			      struct spi_stm32_data *data)
{
	if (cfg->fifo_enabled) {
		spi_stm32_shift_fifo(cfg->spi, data);
	} else {
		printk("@1");
		while (!ll_func_tx_is_not_full(cfg->spi)) {
			/* NOP */
		}

		printk("@2%x", LL_SPI_ReadReg(cfg->spi, SR));
		spi_stm32_send_next_frame(cfg->spi, data);

		printk("@3");
		uint8_t loop_count = 0;
		uint32_t error_count = 0;
		while (!ll_func_rx_is_not_empty(cfg->spi)) {
			loop_count++;
			if ((loop_count == 0) && (error_count < 5)) {
				printk("\t%x\n",LL_SPI_ReadReg(cfg->spi, SR));
				error_count++;
			}
			/* NOP */
		}
		printk("@4");

		spi_stm32_read_next_frame(cfg->spi, data);
		printk("@5\n");
	}
}

in the while (!ll_func_rx_is_not_empty(cfg->spi)) ...

A debug output run:

uart:~$ sketch
Enter transceive(0x805bb18 0x2400f568 0x2400d350 0x2400d360)
spi_stm32_[00:00:12.460,000] <inf> usb_cdc_acm: Device suspended
configure(0x805bb18, 0x2400f568)
        freq: 3000000 clock:120000000 br:6
        hardware CS
[00:00:12.473,000] <dbg> spi_ll_stm32: spi_stm32_configure: Installed config 0x2400f568: freq 1875000Hz (div = 64), mode 0/0/0, slave 0
[00:00:12.485,000] <dbg> spi_ll_stm32: spi_context_buffers_setup: tx_bufs 0x2400d350 - rx_bufs 0x2400d360 - 1
[00:00:12.496,000] <dbg> spi_ll_stm32: spi_context_buffers_setup: current_tx 0x2400d348 (1), current_rx 0x2400d358 (1), tx buf/len 0x2400d33f/1, rx buf/len 0x2400d347/1
        Call LL_SPI_StartMasterTransfer
        returned - Wait while !
        IsActiveMasterTransfer
        Call spi_stm32_cs_control
SPI: 0x40015000 00000201 00000000 50070007 20400000 00000000 00001002 00000000 00000000
RCC: clks:00000000 RST 1:0 5:0 EN 1:1000 5:100000
SPI init called on: 0x40013000 0x40015000 0 0 0
        Call ll_func_enable_int_errors
        Call ll_func_enable_int_tx_empty
I:1002 3e3
SPI pins: 5 5 5 : SPI1 2 3 1
SF M N
@1@21002[00:00:12.548,000] <dbg> spi_ll_stm32: spi_context_update_tx: tx buf/len 0/0
@3      1002
        1002
        1002
        1002
        1002

I also have had it running with Logic Analyzer hooked up to pins 10-13, and only pin 10 showed anything.
So I wondered about what were the IO pins for SPI1 configured for:

So I added the following to the start of the transfer code... Actually to the start of the ISR...

static void spi_stm32_isr(const struct device *dev)
{
	const struct spi_stm32_config *cfg = dev->config;
	struct spi_stm32_data *data = dev->data;
	SPI_TypeDef *spi = cfg->spi;
	int err;

	printk("I:%x %x\n", LL_SPI_ReadReg(spi, SR), LL_SPI_ReadReg(spi, IER));
	// PB3 PD7 PG9 : PH6 PJ10 PJ11
	printk("SPI pins: %x %x %x : SPI1 %x %x %x\n",
		(GPIOB->AFR[0] >> (3 * 4 )) & 0xf, (GPIOD->AFR[0] >> (7 * 4 )) & 0xf, (GPIOG->AFR[1] >> ((9-8) * 4 )) & 0xf,
		(GPIOH->AFR[0] >> (6 * 4 )) & 0xf, (GPIOJ->AFR[1] >> ((10-8) * 4 )) & 0xf, ((GPIOJ->AFR[1] >> ((11-8) * 4 )) & 0xf));

I ran the sketch using only SPI1, but the output was shown above, but:
SPI pins: 5 5 5 : SPI1 2 3 1
The SPI (spi1) pins make sense as the Alternate functions for those pins are:

Image
The one for SPI1 (spi5) - don't, need to double check pin 13s one but the other two are timers
Image

Then remembered that these pins were added to the PWM list, and I am guessing probably all of the pins from pin2-13
currently have their alternate pin function set to the PWM timer used.

I did a quick and dirty removal of the timer entries for pins 11-13 from the overlay and rebuilt and then SPI1 started working again.

Will probably introduce a PR to do this, at least for now. Hopefully at some point there will be a system in place that allows
the sketch to select what usage that want for each pin. I know that there is a discussion going on with zephyr on this.

The good news is that I am learning a lot more about parts of the system :D The bad news is, it took a lot longer to figure this out
than it should have.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions