Как исправить код с передачей 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.

  1. 0x03 - установить режим конфигурации ввода / вывода расширителя
  2. 0x0 - сделать все выводы выходами
  3. 0x01 - перейти в режим вывода
  4. 0xa8 - включить один из выходов расширителя.

Также я посмотрел официальные фрагменты для серии F0, где был аналогичный пример I2C, но не было подробного процесса передачи от мастера.

Не могли бы вы помочь мне найти ошибку?

0 ответов

Другие вопросы по тегам