33#define SYSCLK_HZ 48000000u
35#define REINIT_MS 1000u
37static volatile uint32_t
s_ms;
47 FLASH->ACR = (FLASH->ACR & ~FLASH_ACR_LATENCY) | FLASH_ACR_LATENCY_0;
48 while ((FLASH->ACR & FLASH_ACR_LATENCY) != FLASH_ACR_LATENCY_0) { }
49 RCC->CR &= ~RCC_CR_HSIDIV;
50 SystemCoreClockUpdate();
54static void gpio_mode(GPIO_TypeDef *g, uint32_t pin, uint32_t mode, uint32_t af)
56 g->MODER = (g->MODER & ~(3u << (2u * pin))) | (mode << (2u * pin));
57 g->OSPEEDR |= 3u << (2u * pin);
58 volatile uint32_t *afr = &g->AFR[pin >> 3];
59 *afr = (*afr & ~(0xFu << (4u * (pin & 7u)))) | (af << (4u * (pin & 7u)));
64 RCC->IOPENR |= RCC_IOPENR_GPIOAEN | RCC_IOPENR_GPIOBEN;
65 RCC->APBENR1 |= RCC_APBENR1_I2C1EN;
66 RCC->APBENR2 |= RCC_APBENR2_SPI1EN | RCC_APBENR2_TIM14EN;
70 GPIOA->BSRR = (1u << 4) | (1u << 2) | (1u << 8);
79 GPIOB->OTYPER |= (1u << 6) | (1u << 7);
86 TIM14->EGR = TIM_EGR_UG;
87 TIM14->CR1 = TIM_CR1_CEN;
90 SPI1->CR1 = SPI_CR1_MSTR | SPI_CR1_CPOL | SPI_CR1_CPHA | SPI_CR1_SSM | SPI_CR1_SSI |
91 (4u << SPI_CR1_BR_Pos);
92 SPI1->CR2 = (7u << SPI_CR2_DS_Pos) | SPI_CR2_FRXTH;
93 SPI1->CR1 |= SPI_CR1_SPE;
99 I2C1->TIMINGR = (5u << I2C_TIMINGR_PRESC_Pos) | (3u << I2C_TIMINGR_SCLDEL_Pos) |
100 (2u << I2C_TIMINGR_SDADEL_Pos) | (3u << I2C_TIMINGR_SCLH_Pos) | 9u;
102 I2C1->OAR1 = I2C_OAR1_OA1EN | ((uint32_t)
FLOW_I2C_ADDR << 1);
103 I2C1->CR1 = I2C_CR1_ADDRIE | I2C_CR1_RXIE | I2C_CR1_TXIE | I2C_CR1_STOPIE |
104 I2C_CR1_NACKIE | I2C_CR1_ERRIE | I2C_CR1_PE;
105 NVIC_SetPriority(I2C1_IRQn, 0);
106 NVIC_EnableIRQ(I2C1_IRQn);
111 DBG->APBFZ1 |= DBG_APB_FZ1_DBG_IWDG_STOP;
116 while (IWDG->SR != 0u) { }
123 const uint32_t isr = I2C1->ISR;
124 if (isr & I2C_ISR_ADDR) {
125 if (isr & I2C_ISR_DIR) {
126 I2C1->ISR |= I2C_ISR_TXE;
131 I2C1->ICR = I2C_ICR_ADDRCF;
135 if (isr & I2C_ISR_NACKF) I2C1->ICR = I2C_ICR_NACKCF;
136 if (isr & I2C_ISR_STOPF) {
137 I2C1->ICR = I2C_ICR_STOPCF;
138 I2C1->ISR |= I2C_ISR_TXE;
141 if (isr & (I2C_ISR_BERR | I2C_ISR_ARLO | I2C_ISR_OVR))
142 I2C1->ICR = I2C_ICR_BERRCF | I2C_ICR_ARLOCF | I2C_ICR_OVRCF;
149 const uint32_t step = (us > 10000u) ? 10000u : us;
150 const uint16_t t0 = (uint16_t)TIM14->CNT;
151 while ((uint16_t)((uint16_t)TIM14->CNT - t0) < step) { }
159 while (!(SPI1->SR & SPI_SR_TXE)) { }
160 *(
volatile uint8_t *)&SPI1->DR = b;
161 while (!(SPI1->SR & SPI_SR_RXNE)) { }
162 return *(
volatile uint8_t *)&SPI1->DR;
165static void pin_cs(uint8_t l) { GPIOA->BSRR = l ? (1u << 4) : (1u << (4 + 16)); }
166static void pin_reset(uint8_t l) { GPIOA->BSRR = l ? (1u << 2) : (1u << (2 + 16)); }
167static void led(uint8_t on) { GPIOA->BSRR = on ? (1u << (8 + 16)) : (1u << 8); }
182 uint16_t last_us = (uint16_t)TIM14->CNT;
183 uint8_t reads_seen =
bridge_reads(), fc_active = 0, valid = 1;
195 last_us = (uint16_t)TIM14->CNT;
198 if ((int32_t)(
s_ms - t_next) >= 0) {
204 const uint16_t now_us = (uint16_t)TIM14->CNT;
205 const uint32_t dt = (uint16_t)(now_us - last_us);
216 fc_active = (uint8_t)((
s_ms - t_reads) < 1000u);
218 if (!ok)
led((
s_ms / 100u) & 1u);
219 else if (!valid)
led((
s_ms % 2000u) < 50u);
220 else if (!fc_active)
led((
s_ms / 500u) & 1u);
Register file of the flow bridge and the I2C target protocol.
void bridge_add_sample(int16_t dx, int16_t dy, uint8_t squal, uint16_t shutter, uint8_t valid, uint32_t dt_us)
one motion burst: deltas since the previous burst, dt_us = time between the two bursts; valid = 0 for...
void bridge_i2c_addr_read(void)
address matched, master reads: snapshot
void bridge_i2c_addr_write(void)
address matched, master writes
void bridge_i2c_rx(uint8_t b)
first byte = register pointer
void bridge_set_sensor_ok(uint8_t ok)
uint8_t bridge_reads(void)
FRAME reads since boot (LED activity), wraps.
uint8_t bridge_take_ctrl(void)
CTRL bits written by the master, cleared.
uint8_t bridge_i2c_tx(void)
next byte to send
void bridge_i2c_stop(void)
I2C register map of the ACwing Flow bridge (STM32C011 at 0x3B).
static void iwdg_feed(void)
static void board_init(void)
static void pin_cs(uint8_t l)
static void pin_reset(uint8_t l)
static void led(uint8_t on)
static volatile uint32_t s_ms
static void clock_init(void)
void SysTick_Handler(void)
static const pmw_bus_t k_bus
static uint8_t spi_xfer(uint8_t b)
void I2C1_IRQHandler(void)
static void iwdg_start(void)
static void delay_us(uint32_t us)
static void gpio_mode(GPIO_TypeDef *g, uint32_t pin, uint32_t mode, uint32_t af)
PixArt PMW3901MB optical flow sensor over SPI (mode 3, <= 2 MHz).
int pmw_init(const pmw_bus_t *bus)
0 = product id ok, configured
uint8_t pmw_valid(const pmw_burst_t *b)
PixArt rule: SQUAL < 0x19 with the shutter at its maximum = no usable features.
void pmw_burst(pmw_burst_t *b)
motion burst (register 0x16)