Created 2022-10-30 Updated 2023-04-16
RAM: 128k
FLASH: 512k
CLOCK: 100MHz, but default seems to be 16MHz
libopencm32 example dma mem-to-mem for stm32f1
SCL and SDA lines should be set to open-drain.
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); } }
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.
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
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
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
main(): HAL_TIM_Base_Start_IT(&htim2);
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