Как исправить код с передачей I2C на STM32F334K8T6? (Не работает)
В течение нескольких дней я изучал работу I2C для управления несколькими расширителями ввода-вывода PCA9534PW с помощью STM32F334K8T6.
Я изучил документацию и придумал код (я не работаю с HAL, так как меня интересует понимание регистров).
#include "main.h"
#include "stdio.h"
// Functions
/*** Clock and timers sections ***/
// System clock settings
int systemClockInit() {
// Start clock sequence
/*
1 - RUN HSE + WAIT ready
2 - Configure PLL
3 - EN PLL + WAIT ready
4 - Set flash wait cycles
5 - Set bus divider
6 - Switch to PLL mode
7 - Disable HSI (Optional)
*/
// Body
int waitCounter = 0;
// & - bit "AND" -> 1 & 1 = 1 or = 0 (Compare bits)
// Run HSE clock (HSEON - 16bit)
// 1 << 16 -> turn on 1 on 16 bit
RCC->CR |= (1 << 16);
// HSEREADY wait
for(waitCounter = 0; ; waitCounter++) {
if(RCC->CR & (1 << 17)) { break; } // If HSE success enabled
if(waitCounter > 0x1000) {
// Clear HSEON bit
// (Replace 1 - 0 / 0 - 1, bit and - clear 16 bit, save other)
RCC->CR &= ~(1 << 16);
return 1;
}
}
// Configure PLL
// 24mHz (x3)
RCC->CFGR |= (0x1 << 18) // PLL x3 (0x1 = 0001), 18 - start PLLMULL sector
| (0x01 << 16); // Enable PLL src on HSE clock
// Enable PLL
RCC->CR |= (1 << 24); // 24 bit - PLLON
// PLL enable WAIT
for(waitCounter = 0; ; waitCounter++) {
if(RCC->CR & (1 << 25)) { break; } // If PLL success enabled
if(waitCounter > 0x1000) {
RCC->CR &= ~(1 << 16); // Disable HSE
RCC->CR &= ~(1 << 24); // Disable PLL
return 2;
}
}
// Set flash wait counter and bus divider
// Core frequency = 24mHz -> set zero wait cycles
FLASH->ACR |= (0x00 << 0); // 0x00 = 000, 0 latency position sector
// Set bus dividers
RCC->CFGR |= (0x00 << 11) // PPRE2 divider disabled (000)
// For < 36mHz
| (0x00 << 8) // APB1 divider disabled (000)
// Wait reconnect to PLL
RCC->CFGR |= (0x02 << 0);
while((RCC->CFGR & 0x08) != (0x02 << 2)) {} // 0x08 - RCC_CFGR_SWS_MSK (00001100). 0x02 - 00000010 - PLL selected sysclk, 2 - SWS bits position
// Disabled HSI clock
RCC->CR &= ~(1 << 0); // Disabled HSI
// Return 0 (Success)
return 0;
}
void I2C_Init(void);
void I2C_Start(void);
void I2C_WriteData(void);
// Main function
int main(void)
{
// System Clock init
systemClockInit();
//printf("State: %d", state);
RCC->AHBENR |= (1 << 17) | (1 << 18); // PORTA and PORTB clock enabled
// Configure ms timer
#define coreFrequency 24000000 // 72mHz core frequency
SysTick_Config(coreFrequency / 1000);
I2C_Init();
I2C_Start();
// Loop
while (1)
{
I2C_WriteData();
}
}
void I2C_Init(void) {
RCC->AHBENR |= RCC_AHBENR_GPIOBEN; // PORT B clock EN
// I2C pins settings
GPIOB->OTYPER |= GPIO_OTYPER_OT_6 | GPIO_OTYPER_OT_7; // Open-Drain PB6, PB7
GPIOB->AFR[0] |= (0x04 << 16); // AF4 (PORTB)
GPIOB->OSPEEDR &= ~GPIO_OSPEEDER_OSPEEDR6; // AF (PB6)
GPIOB->OSPEEDR &= ~GPIO_OSPEEDER_OSPEEDR7; // AF (PB7)
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; // EN i2c clock
// I2C bus settings
//RCC->APB1RSTR |= (1 << 21); // I2C reset
I2C1->CR1 |= (0 << 0); // I2C peripheral disabled
I2C1->CR1 |= (1 << 12); // I2C analog filter disabled
I2C1->TIMINGR |= 0x00506682; // I2C timing (0x2000090E)
I2C1->CR1 |= (1 << 17); // Clock stretching disabled
I2C1->CR1 |= (1 << 1); // Enable TXIS interrupt
I2C1->CR1 |= (1 << 0); // I2C peripheral enabled
}
void I2C_Start(void) {
while(I2C1->ISR & 15); // wait untin bus not busy
I2C1->CR2 |= (0x4 << 16); // 4 bytes (NBYTE)
I2C1->CR2 |= (1 << 25); // AUTOEND EN
I2C1->CR2 |= (0x20 << 0); // Slave address
I2C1->CR2 |= (1 << 13); // Set START
}
void I2C_WriteData(void) {
static int byteCounter = 0;
if((I2C1->ISR & 1) && !byteCounter) {
I2C1->TXDR = 0x03; // send byte #1
byteCounter++;
return;
}
else if((I2C1->ISR & 1) && byteCounter == 1) {
I2C1->TXDR = 0x0; // send byte #2
byteCounter++;
return;
}
else if((I2C1->ISR & 1) && byteCounter == 3) {
I2C1->TXDR = 0x01; // send byte #3
byteCounter++;
return;
}
else if((I2C1->ISR & 1) && byteCounter == 4) {
I2C1->TXDR = 0xf8; // send byte #4
byteCounter++;
return;
}
}
Частота шины APB1 = 24 МГц (таймер должен работать).
Частота I2C 100 кГц, режим MASTER.
Я просто хочу отправить 4 байта на устройство с адресом 0x20.
- 0x03 - установить режим конфигурации ввода / вывода расширителя
- 0x0 - сделать все выводы выходами
- 0x01 - перейти в режим вывода
- 0xa8 - включить один из выходов расширителя.
Также я посмотрел официальные фрагменты для серии F0, где был аналогичный пример I2C, но не было подробного процесса передачи от мастера.
Не могли бы вы помочь мне найти ошибку?