Page 1 of 1

SPI1 on STM32F103

Posted: Tue Mar 29, 2022 5:13 pm
by AnSc
Hi,

I'm new to STM32 development. I did some projects in the past with Atmel controllers, but started a new project using the STM32F103.
I built a keyboard with this processor last year and the firmware for this uses Chibios too. And I got it up and running after a bit of research and support from various people. So I thought I can use it in a new project without to much trouble…

I'm now several days looking why I cannot get the SPI1 interface running.
I have a small demo running using NIL which toggles two LEDs and sends some text via UART.

But as soon as I try to do anything on SPI the controller stops. The debugger (hoping I use it correctly) says something about unhandled exception in this state.

When I build the project I get a warning that gives me no clue:
c:\chibistudio\chibios2111\os\hal\ports\stm32\lld\gpiov1\hal_pal_lld.h:81:3: warning: initialization of 'void (*)(SPIDriver *)' {aka 'void (*)(struct hal_spi_driver *)'} from 'long unsigned int' makes pointer from integer without a cast [-Wint-conversion]

I tried several projects that use SPI in some way but could not find a good starting point since none seems to use SPI1.

I'm not sure if I found all required points I need to address to get it running.
What I did regarding SPI:

./board/board.c:

Code: Select all

void boardInit(void) {
  //JTAG-DP Disabled and SW-DP Enabled
  AFIO->MAPR |= AFIO_MAPR_SWJ_CFG_JTAGDISABLE;
  AFIO->MAPR |= AFIO_MAPR_TIM3_REMAP_FULLREMAP; //map timer 3 to port C
  AFIO->MAPR |= AFIO_MAPR_SPI1_REMAP; // enable SPI1
}


./board/board.h:

Code: Select all

#define LINE_SPI1_NSS       PAL_LINE(GPIOA,  4)    // pin 20


/*
 * Port A setup.
 * Everything input with pull-up except:
 * PA0..4       - Normal output, PA4 SPI NSS
 * PA5,7        - Alternate output SPI SCK, MOSI
 * PA9          - Output USART
 * PA10         - Input USART
 * PA11,12      - USB
 */
#define VAL_GPIOACRL            0xB8B33333      /*  PA7...PA0 */
#define VAL_GPIOACRH            0x888884B8      /* PA15...PA8 */
#define VAL_GPIOAODR            0xffffffff


./cfg/halconf.ha

Code: Select all

/**
 * @brief   Enables the SPI subsystem.
 */
#if !defined(HAL_USE_SPI) || defined(__DOXYGEN__)
#define HAL_USE_SPI                         TRUE
#endif

/*===========================================================================*/
/* SPI driver related settings.                                              */
/*===========================================================================*/

/**
 * @brief   Enables synchronous APIs.
 * @note    Disabling this option saves both code and data space.
 */
#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__)
#define SPI_USE_WAIT                        TRUE
#endif

/**
 * @brief   Inserts an assertion on function errors before returning.
 */
#if !defined(SPI_USE_ASSERT_ON_ERROR) || defined(__DOXYGEN__)
#define SPI_USE_ASSERT_ON_ERROR             TRUE
#endif

/**
 * @brief   Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs.
 * @note    Disabling this option saves both code and data space.
 */
#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define SPI_USE_MUTUAL_EXCLUSION            FALSE
#endif

/**
 * @brief   Handling method for SPI CS line.
 * @note    Disabling this option saves both code and data space.
 */
#if !defined(SPI_SELECT_MODE) || defined(__DOXYGEN__)
//#define SPI_SELECT_MODE                     SPI_SELECT_MODE_PAD
#define SPI_SELECT_MODE                     SPI_SELECT_MODE_LINE
#endif

(As a side note: when I set SPI_USE_WAIT to FALSE I get a compile error: "../../../Chibistudio/chibios2111/os/hal/ports/STM32/LLD/SPIv1/hal_spi_v2_lld.c:239:50: error: macro "__spi_wakeup_isr" passed 2 arguments, but takes just 1")

./cfg/mcuconf.h

Code: Select all

#define STM32F103_MCUCONF

#define STM32_SPI_USE_SPI1                  TRUE


./main.c

Code: Select all

/** Maximum speed SPI configuration (9MHz, CPHA=0, CPOL=0, MSb first).   */
static const SPIConfig hs_spicfg = {
  false,  // disable circular mode
  NULL,   // no callback
  LINE_SPI1_NSS,  // CS line, requires SPI_SELECT_MODE SPI_SELECT_MODE_LINE in halconf.h
  SPI_CR1_BR_0,  // BR0 set for 9 MHz (STM32_PPRE1/4)
  0    // use ChibiOS defaults
};

THD_WORKING_AREA(waThread4, 128);
THD_FUNCTION(Thread4, arg) {
  (void)arg;
  /* enable power to OLED */
  palSetLine(LINE_LCD_EN);
  /* disable CS line */
  palSetLine(LINE_SPI1_NSS);
  /*
   * Activates SPI driver 1 using the driver default configuration.
   */
  static const uint8_t payload[1] = {0xa5}; // dummy buffer
  /* initialize SPI port 1 */
  spiStart(&SPID1, &hs_spicfg);
  /* reset OLED */
  //oledReset();

  while (true) {
    oledReset(); // pull down Reset, wait 500 ms, pull up Reset
//    spiSelect(&SPID1);  // if enabled this line causes the controller to stop
//    spiSend(&SPID1, 1, &payload);
 //   spiUnselect(&SPID1);
    chThdSleepMilliseconds(2000);
  }
}

THD_TABLE_BEGIN
  THD_TABLE_THREAD(0, "blinker1", waThread1, Thread1, NULL)
  THD_TABLE_THREAD(1, "blinker2", waThread2, Thread2, NULL)
  THD_TABLE_THREAD(2, "hello",    waThread3, Thread3, NULL)
  THD_TABLE_THREAD(3, "spi",      waThread4, Thread4, NULL)
THD_TABLE_END


I hope that helps to locate my error or where I need to add something.

As an aside: I tried to implement this as RT also but this did not even run with just a blinker task. From the debugger it looked to me that it was stuck in the (empty) main loop. Therefore, I try to implement it in NIL.

Re: SPI1 on STM32F103

Posted: Tue Mar 29, 2022 6:10 pm
by Giovanni
Hi,

Which version are you using?

The demo in /testhal/STM32/multi/SPI uses SPI1 on the F1 and compiles fine (testing the latest code in trunk).

Examples of configurations:

Code: Select all

/*
 * Circular SPI configuration (18MHz, CPHA=0, CPOL=0, MSb first).
 */
const SPIConfig c_spicfg = {
  .circular         = true,
  .slave            = false,
  .data_cb          = spi_circular_cb,
  .error_cb         = spi_error_cb,
  .ssport           = GPIOA,
  .sspad            = GPIOA_SPI1NSS,
  .cr1              = 0U,
  .cr2              = 0U
};

/*
 * Maximum speed SPI configuration (18MHz, CPHA=0, CPOL=0, MSb first).
 */
const SPIConfig hs_spicfg = {
  .circular         = false,
  .slave            = false,
  .data_cb          = NULL,
  .error_cb         = spi_error_cb,
  .ssport           = GPIOA,
  .sspad            = GPIOA_SPI1NSS,
  .cr1              = 0U,
  .cr2              = 0U
};

/*
 * Low speed SPI configuration (281.250kHz, CPHA=0, CPOL=0, MSb first).
 */
const SPIConfig ls_spicfg = {
  .circular         = false,
  .slave            = false,
  .data_cb          = NULL,
  .error_cb         = spi_error_cb,
  .ssport           = GPIOA,
  .sspad            = GPIOA_SPI1NSS,
  .cr1              = SPI_CR1_BR_2 | SPI_CR1_BR_1,
  .cr2              = 0U
};


Try starting from that demo configurations, also look at settings in halconf.h and mcuconf.h.

Giovanni

Re: SPI1 on STM32F103

Posted: Tue Mar 29, 2022 10:18 pm
by AnSc
Hi Giovanni,

thanks for the feedback, I'm using version 21.11.

Found it and will do some reading. Looks like a RT implementation, I hope to learn from this.
I will give it a try in the next days. :)

André

Re: SPI1 on STM32F103

Posted: Wed Mar 30, 2022 6:44 pm
by AnSc
I gave it a try today.
I took the "olimex" port and adapted it to my board.

The LED is flashing and the SPI threads seem to run alternatively according to the debugger.

However, I cannot measure any signal change on the corresponding signals. No clock and no data is sent out. Chip select is toggled, however.

An additional trhead I inserted sends successfully data over UART1.

Is there anything I'm missing? Are there any settings I could check that maybe collide and prevent the SPI data being sent out?

Re: SPI1 on STM32F103

Posted: Wed Mar 30, 2022 7:20 pm
by Giovanni
Hi,

I would check GPIO/AFIO settings. Make sure to create proper "board files" with all your GPIO initialization data.

Giovanni

Re: SPI1 on STM32F103

Posted: Thu Mar 31, 2022 1:21 pm
by AnSc
Thanks for the pointer. This helped me a lot. :)

I found that setting the appropriate bits in board.h already yields the desired result.
However, when I set

Code: Select all

AFIO->MAPR |= AFIO_MAPR_SPI1_REMAP;
I see no output. Leaving this line out it works.

Do I interpret this correctly that by just setting the output to Alternate the first alternate in the datasheet/signal list is active?

But then, what does AFIO_MAPR_SPI1_REMAP achieve? Is this only required when SPI1 is used on port B where it is declared in the Remap column?

Re: SPI1 on STM32F103

Posted: Thu Mar 31, 2022 1:42 pm
by Giovanni
Hi,

This mess is caused by the old remap mechanism on ST32F1, there are also some errata about it.

In general if you don't do any remap then the alternate pin is the default one.

Giovanni