💾 Archived View for blinkyshark.chickenkiller.com › f411.gmi captured on 2023-06-16 at 16:17:00. Gemini links have been rewritten to link to archived content

View Raw

More Information

-=-=-=-=-=-=-

stm32f411re

Created 2022-10-30 Updated 2023-04-16

RAM: 128k

FLASH: 512k

CLOCK: 100MHz, but default seems to be 16MHz

DMA

libopencm32 example dma mem-to-mem for stm32f1

I2C

SCL and SDA lines should be set to open-drain.

DMA

I2C bare metal, by Hackaday

LL drivers I2C DMA

SPI

Bit-banging SPI master TX

static void spi_out(uint8_t n) 
{
	for (uint8_t i = 8; i--; n <<= 1) {
		digitalWrite(MOSI, n>>7);
		digitalWrite(SCK, HIGH); 
		digitalWrite(SCK, LOW);
	}
}

CMSIS SPI master TX

Perform peripheral setup. Then:

  SPI1->CR1 |= SPI_CR1_SPE; // enable SPI
  int i = 0;
  while(1)
  {
	  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);

          // rougly equiv of   HAL_SPI_Transmit(&hspi1, (uint8_t*) &i, 1, 100); :
	  while(!(SPI1->SR & SPI_SR_TXE));
	  SPI1->DR = i;
	  while(!(SPI1->SR & SPI_SR_TXE)); // takes about 1.1us
	  while((SPI1->SR & SPI_SR_BSY)); // takes about 3.8us

	  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);
	  i++;

The timings above assume a transfer rate of 1.56MB/s. The whole transmission takes about 5.4us.

SPI bare metal, by Hackaday

SSD1306

On blackpill, my SSD1306 seemed to require a delay of 4ms before initialisation of SSD1306, otherwise it would require toggling of the NRST button. This problem occurred on both the Cube and libopencm3, so I don't think it's a coding error per se.

/home/pi/repos/rpi/stm32f411re/libopencm3/15-ssd1306

WEAK OVERRIDE

/home/pi/repos/rpi/stm32f411re/libopencm3/11-ledmat-i2c

TIMERS and Delay

Capabilities:

TIM BITS
2    32
3    16
4    16
5    32

PSC for all timers (1,2,3,4,5,9.10) are 16-bits

Microsocend delay using timer

Uses TIM3 as an example, and toggles a pin every 1ms. No interrupts are used because we don't need them in this example.

  RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; // Enable clock. NB TIM 1,9,10, 11 is on a different clock
  TIM3->PSC = 100-1; // assumes clock is 100MHz. Clock will increase CNT every 1us
  TIM3->CR1 |= TIM_CR1_ARPE; // enable reload (i.e. wrapping)
  TIM3->CR1 |= TIM_CR1_CEN; // enable the timer

  uint32_t cnt = TIM3->CNT;
  while (1)
  {
	  while ((uint16_t)(TIM3->CNT - cnt) < 1000); // cast to uint16_t because TIM3 overflows at 16 bits
	  cnt += 1000;
	  HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_10);
  }

Delay Microsecond Millisecond Utility | DWT Delay & Timer Delay

HAL

main(): HAL_TIM_Base_Start_IT(&htim2);

LL

In CubeMX you will want to enable ARR preload, unless it is a one-shot.

main():

LL_TIM_EnableCounter(TIM2);
LL_TIM_EnableIT_UPDATE(TIM2);

IRQ:

void TIM2_IRQHandler(void)
{
  LL_TIM_ClearFlag_UPDATE(TIM2); // necessary
  ... // etc.
  LL_GPIO_TogglePin(GPIOC, LL_GPIO_PIN_0);
}

Change frequency:

LL_TIM_SetAutoReload(TIM2, 400);
LL_TIM_GenerateEvent_UPDATE(TIM2); // possibly not necessary

EXITS

Bare metal programming guide

STM32 World Wiki