STM32F103 problem z odpaleniem I2C

Tu możesz pisać o swoich problemach z pisaniem programów w języku C/C++ dla STM.
Awatar użytkownika
squeez
User
User
Posty: 211
Rejestracja: czwartek 04 lut 2016, 10:13

STM32F103 problem z odpaleniem I2C

Postautor: squeez » niedziela 03 lip 2016, 00:27

Męczę się już cały dzień :)
Chciałbym odpalić OLED-a po I2C ale utknąłem na samym początku czyli komunikacji.

Czytam RM wte i nazad ale coś kiepsko mi idzie.

Funkcja do inicjalizacji:

Kod: Zaznacz cały

void I2C_Init(void)
{
   // I2C GPIO CONFIG
   GPIOB->CRL |= GPIO_CRL_CNF6 | GPIO_CRL_CNF7 | GPIO_CRL_MODE6 | GPIO_CRL_MODE7;

   // Software reset I2C
   I2C1->CR1 |= I2C_CR1_SWRST;
   I2C1->CR1 &= ~I2C_CR1_SWRST;

   I2C1->CR1 &= ~I2C_CR1_PE;
   I2C1->CR2 = I2C_CR2_FREQ_3; // 8MHz HSI
   I2C1->TRISE |= 9;
   I2C1->CCR = 80;

   // Wlaczenie I2C
   I2C1->CR1 |= I2C_CR1_PE | I2C_CR1_ACK;
   I2C1->OAR1 = (1 << 14);
}


Zegar dla szyny włączam nieco wcześniej (RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;)
Do I2C1->CR2 wpisuję 8 (tak wynika z dokumentacji).
I2C1->TRISE = 9 też z RM tam jest (1000 ns / 125 ns = 8 + 1)
I2C1->CCR z tym mam największy problem ale dla 100kHz powinno być 80 czy 160?

potem mam funkcje:

Kod: Zaznacz cały

void I2C_Start(void)
{
   I2C1->CR1 |= I2C_CR1_START;
   while( !(I2C1->SR1 & I2C_SR1_SB) );
}

void I2C_Stop(void)
{
   I2C1->CR1 |= I2C_CR1_STOP;
}

void I2C_SendAddr(uint8_t address)
{
   I2C1->DR = address & ~I2C_OAR1_ADD0;
   while(  !(I2C1->SR1 & I2C_SR1_ADDR) );
   uint16_t dummy = I2C1->SR2;
}

void I2C_SendByte(uint8_t byte)
{
   while( !( I2C1->SR1 & I2C_SR1_TXE ));
   I2C1->DR = byte;
}


Ale i tak wisi mi na pierwszej pętli po wysłaniu start, czyli tu: while( !(I2C1->SR1 & I2C_SR1_SB) );

Prosił bym o jakieś nakierowanie gdzie robię błąd :)

Awatar użytkownika
Antystatyczny
Geek
Geek
Posty: 1168
Rejestracja: czwartek 03 wrz 2015, 22:02

Re: STM32F103 problem z odpaleniem I2C

Postautor: Antystatyczny » niedziela 03 lip 2016, 01:01

A to: I2C1->CR2 = I2C_CR2_FREQ_3; // 8MHz HSI faktycznie wpisuje wartość dziesiętną 8 w bity FREQ [5:0]? U mnie nigdzie nie ma makra I2C_CR2_FREQ_3

Ok, dogrzebałem się do tego makra w CMSIS. Tak czy siak coś mi tu nie gra. Ty masz zegar 8MHz, a w CCR ustawiasz 80 i zastanawiasz się nad 160. W RM zaś napisane jest jak byk:

For instance: in Sm mode, to generate a 100 kHz SCL frequency:
If FREQR = 08, TPCLK1 = 125 ns so CCR must be programmed with 0x28
(0x28 <=> 40d x 125 ns = 5000 ns.)


No i wygląda na to, że musisz wpisać wartość dziesiętną 40
"The true sign of intelligence is not knowledge but imagination" Albert Einstein.

Awatar użytkownika
Antystatyczny
Geek
Geek
Posty: 1168
Rejestracja: czwartek 03 wrz 2015, 22:02

Re: STM32F103 problem z odpaleniem I2C

Postautor: Antystatyczny » niedziela 03 lip 2016, 01:30

Zapytasz pewnie dlaczego 40, a nie 80. Otóż wczytałem się nieco uważniej w RM i dotarło do mnie, że wartość wpisana w CCR ustala czas trwania POŁOWY okresu na pinie SCL. A skoro tak, to CCR (40 dziesiętnie) * 125ns = 5us. 5us wysokiego poziomu + 5us niskiego poziomu daje nam 10us okres, czyli 100kHz częstotliwość.
"The true sign of intelligence is not knowledge but imagination" Albert Einstein.

Awatar użytkownika
Antystatyczny
Geek
Geek
Posty: 1168
Rejestracja: czwartek 03 wrz 2015, 22:02

Re: STM32F103 problem z odpaleniem I2C

Postautor: Antystatyczny » niedziela 03 lip 2016, 02:08

Aha, zegar dla GPIO podłączanych pod moduł I2C1 również należy włączyć zanim wydasz jakąkolwiek komendę modułowi GPIO. Napisałeś, że włączyłeś zegar dla modułu I2C1, a o GPIO nie wspomniałeś. Dlatego ja o tym wspominam.
Przejrzałem raz jeszcze rejestry i skonfrontowałem z Twoim kodem. Wydaje mi się, że reszta jest ok, ale to się okaże w praniu.

edit:

A jednak coś mi tu nie gra. Zerknij na tę linijkę:

GPIOB->CRL |= GPIO_CRL_CNF6 | GPIO_CRL_CNF7 | GPIO_CRL_MODE6 | GPIO_CRL_MODE7;

Gdy spojrzysz do RM zauważysz, że do CNF6, CNF7, MODE6 i MODE7 wpisuje się wartości od 0 do 3, a Ty wpisałeś...No właśnie, co wpisałeś? ;)


Pozdrawiam
"The true sign of intelligence is not knowledge but imagination" Albert Einstein.

Awatar użytkownika
squeez
User
User
Posty: 211
Rejestracja: czwartek 04 lut 2016, 10:13

Re: STM32F103 problem z odpaleniem I2C

Postautor: squeez » niedziela 03 lip 2016, 08:42

Zegar dla lini GPIO tez mam tylko wlaczony szybciej w system_init().
GPIO dla linii I2C powinny byc ustawione jako alternatywne, otwarty dren.
czyli bity CNF powinny być 11 to własnie ustawia makro GPIO_CRL_CNF6 pojedyncze bity można ustawić np. GPIO_CRL_CNF6_0 i GPIO_CRL_CNF6_1 i wyjdzie na to samo.Podobnie jest z MODE ustawione na 11.

Mnie interesuje konfiguracja AF
For bidirectional Alternate Functions, the port bit must be configured in Alternate
Function Output mode (Push-Pull or Open-Drain). In this case the input driver is
configured in input floating mode


W tab 27 dla I2C jest podane
GPIO configuration: Alternate function open drain


A co CCR to miałem tam 40 (0x28) i też nic.

Jeszce budzi moje wątpliwości że w RM podane jest by skasować bit SB w rejestrze SR1 należy go odczytać
Cleared by software by reading the SR1 register followed by writing the DR register, or by hardware when PE=0

Ale pętla while czyta ten rejestr, no chyba ze przed pętlą mam go permanentnie odczyta np. tmp = I2C1->SR1;

Awatar użytkownika
Antystatyczny
Geek
Geek
Posty: 1168
Rejestracja: czwartek 03 wrz 2015, 22:02

Re: STM32F103 problem z odpaleniem I2C

Postautor: Antystatyczny » niedziela 03 lip 2016, 11:29

Ok, z bitami w GPIO_CRL się wyjaśniło. O tym kasowaniu bitu SB też czytałem i zasadniczo pętla while czyta ten rejestr, ale można do próby zrobić tak, jak sugerujesz. Zastanawiam się też nad tym sygnałem ACK, który wysyłasz w momencie włączenia modułu I2C1. Kolejna sprawa to część sprzętowa. Masz dołączone rezystory do pinów SDA i SCL?
"The true sign of intelligence is not knowledge but imagination" Albert Einstein.

Awatar użytkownika
squeez
User
User
Posty: 211
Rejestracja: czwartek 04 lut 2016, 10:13

Re: STM32F103 problem z odpaleniem I2C

Postautor: squeez » niedziela 03 lip 2016, 11:56

rezystory podciągające 4k7 mam na SDA i SCL. Bez ACK sprawdzałem (na początku miałem bez) potem dodałem w akcie desperacji :)
Podepnę tez analizator i zobaczę czy start jest generowany albo czy jest przebieg na SCL.

Awatar użytkownika
squeez
User
User
Posty: 211
Rejestracja: czwartek 04 lut 2016, 10:13

Re: STM32F103 problem z odpaleniem I2C

Postautor: squeez » niedziela 03 lip 2016, 23:59

OK udało się odpalić, OLED działa :D

Jakie zrobiłem błędy ... a bo podstawa początkującego, pierwsze nie podłączyłem GPIOB :/ choć pisałem że to zrobiłem bo było w kodzie ale za komentowane a potem pokręciło mi się że to na linie I2C są na porcie A.
Ale to nie jedyne wpadki, gdy na oscyloskopie zobaczyłem przebiegi (jak GPIOB załączyłem) to ustawiłem dokłądnie częstotliwość i dla mojej konfiguracji CCR = 0x24 co daje lekko ponad 100kHz ale OLED cały czas pusty, musiałem przerobić nieco funkcję do "zamykania" połączenia czyli wysyłanie STOP.

Poniżej kod może się komuś przyda, to prymitywna wersja w poolingu ale jak to odpaliłem to teraz będę chciał zrobić komunikację I2C na przerwaniach. tak by wywalić wszystkie while() z funkcji I2C.

Kod: Zaznacz cały

void I2C_Init(void)
{
   // I2C GPIO CONFIG
   GPIOB->CRL |= GPIO_CRL_CNF6 | GPIO_CRL_CNF7 | GPIO_CRL_MODE6 | GPIO_CRL_MODE7;

   // Software reset I2C
   I2C1->CR1 |= I2C_CR1_SWRST;
   I2C1->CR1 &= ~I2C_CR1_SWRST;

   I2C1->CR1 &= ~I2C_CR1_PE;
   I2C1->CR2 = I2C_CR2_FREQ_3;
   I2C1->TRISE = 9;
   I2C1->CCR = 0x24;

   // Wlaczenie I2C
   I2C1->CR1 |= I2C_CR1_PE | I2C_CR1_ACK;
   I2C1->OAR1 = (1 << 14);
}


void I2C_Start(void)
{
   I2C1->CR1 |= I2C_CR1_START;
   while( !(I2C1->SR1 & I2C_SR1_SB) );
   uint32_t tmp = I2C1->SR1;
}

void I2C_Stop(void)
{
   while( !(I2C1->SR1 & I2C_SR1_BTF) );
   I2C1->CR1 |= I2C_CR1_STOP;
}

void I2C_SendAddr(uint8_t address)
{
   I2C1->DR = address;
   while( !(I2C1->SR1 & I2C_SR1_ADDR) );
   uint32_t dummy = I2C1->SR1;
   dummy = I2C1->SR2;
}

void I2C_SendByte(uint8_t byte)
{
   while( !(I2C1->SR1 & I2C_SR1_TXE) );
   I2C1->DR = byte;
}

Awatar użytkownika
squeez
User
User
Posty: 211
Rejestracja: czwartek 04 lut 2016, 10:13

Re: STM32F103 problem z odpaleniem I2C

Postautor: squeez » wtorek 05 lip 2016, 09:55

Kurczaczki ... mam problem uruchomić komunikację na przerwaniach, erratę czytałem, zwiększyłem priorytet dla wyjątku I2C jak sugerowali ale nadal d...

Kod: Zaznacz cały

// Inicjalizacja
void I2C_Init(void)
{
   // I2C GPIO CONFIG
   RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;

   // Software reset I2C
   I2C1->CR1 |= I2C_CR1_SWRST;
   I2C1->CR1 &= ~I2C_CR1_SWRST;

   I2C1->CR1 &= ~I2C_CR1_PE;
   I2C1->CR2 = I2C_CR2_FREQ_3;
   I2C1->TRISE = 9;
   I2C1->CCR = 0x24;
   // Innterupt
   //I2C1->CR2 |= I2C_CR2_ITEVTEN;
   NVIC_EnableIRQ( I2C1_EV_IRQn );

   // I2C GPIO CONFIG
   GPIOB->CRL |= GPIO_CRL_CNF6 | GPIO_CRL_CNF7 | GPIO_CRL_MODE6 | GPIO_CRL_MODE7;

   // Wlaczenie I2C
   I2C1->CR1 |= I2C_CR1_PE | I2C_CR1_ACK;
   I2C1->OAR1 = (1 << 14);
}

// struktura i funkcja do wysyłania danych
typedef struct {
   uint8_t addr;
   uint8_t *data;
   uint8_t len;
   uint8_t state;
} T_i2c;

volatile T_i2c I2C_host;

void I2C_transmit(uint8_t addr, uint8_t *data, uint8_t len)
{
   I2C_host.addr = addr;
   I2C_host.data = data;
   I2C_host.len = len;
   I2C_host.state = 1;

   I2C1->CR2 |= I2C_CR2_ITEVTEN;
   I2C1->CR1 |= I2C_CR1_START;
}

// Obsługa wyjątku
void I2C1_EV_IRQHandler(void)
{
   uint32_t tsr;

   if( (I2C1->SR1 & I2C_SR1_TXE) && I2C_host.state > 2 )
   {
      I2C1->DR = I2C_host.data[I2C_host.state-2];
      I2C_host.state++;

      if( (I2C1->SR1 & I2C_SR1_BTF) || (I2C_host.state > I2C_host.len+1) )
      {
         I2C1->CR1 |= I2C_CR1_STOP;
         I2C1->CR2 &= ~I2C_CR2_ITEVTEN;
         I2C_host.state = 0;
      }
   }

   if( (I2C1->SR1 & I2C_SR1_SB) && I2C_host.state == 1 )
   {
         tsr = I2C1->SR1;
         I2C1->DR = I2C_host.addr;
         I2C_host.state = 2;
   }

   if( (I2C1->SR1 & I2C_SR1_ADDR) && I2C_host.state == 2 )
   {
      tsr = I2C1->SR1;
      tsr = I2C1->SR2;
      I2C1->DR = I2C_host.data[0];
      I2C_host.state = 3;
   }

}

// Wysyłanie danych
uint8_t buff[] = {0x00, 0x40, 0xFF};
I2C_transmit(SLAVE_I2C_ADDRESS, buff, (sizeof buff / sizeof *buff) );


Jeśli miałby ktoś jakieś sugestie, pomysły, działające przykłady ... byłbym wdzięczny.

Awatar użytkownika
Antystatyczny
Geek
Geek
Posty: 1168
Rejestracja: czwartek 03 wrz 2015, 22:02

Re: STM32F103 problem z odpaleniem I2C

Postautor: Antystatyczny » wtorek 05 lip 2016, 10:41

W dokumentacji HAL jest napisane, że przerwania I2C mają mieć najwyższy możliwy priorytet, by NIC nie zakłóciło pracy I2C.
"The true sign of intelligence is not knowledge but imagination" Albert Einstein.

Awatar użytkownika
squeez
User
User
Posty: 211
Rejestracja: czwartek 04 lut 2016, 10:13

Re: STM32F103 problem z odpaleniem I2C

Postautor: squeez » wtorek 05 lip 2016, 11:11

Teraz nie mam kodu przy sobie (został w domu) ale ustawiłem priorytety na 4G i 4S.
Czyli coś w stylu:

Kod: Zaznacz cały

#define PRIGROUP_4G_4S ((const uint32_t) 0x05)

NVIC_SetPriorityGrouping( PRIGROUP_4G_4S );
uint32_t prio;

prio = NVIC_EncodePriority(PRIGROUP_4G_4S, 1, 0);
NVIC_SetPriority(I2C1_EV_IRQn, prio);

prio = NVIC_EncodePriority(PRIGROUP_4G_4S, 2, 0);
NVIC_SetPriority(SysTick_IRQn, prio);


Mam jeszcze przerwanie od TIM1 i EXTI ale TIM1 generuje przerwanie co 2s to raczej nie ma szans by akurat wchodził w drogę, podobnie jak EXTI z przycisku (nie wciskam go).
Jak rozumiem im mniejsza wartość priorytetu, tym jest on ważniejszy, czyli nadanie 1 dla I2C1_EV_IRQn powinno go uczynić najważniejszym (poza tymi o stałych priorytetach jak reset itp.).

@rezasurmar ale to jest transmisja na przerwaniach i działająca na F103?
PS. rejestry są fajne :)

Awatar użytkownika
squeez
User
User
Posty: 211
Rejestracja: czwartek 04 lut 2016, 10:13

Re: STM32F103 problem z odpaleniem I2C

Postautor: squeez » wtorek 05 lip 2016, 12:37

OLED też mi działa ale w poolingu (teoretycznie to nie problem) ale w ramach zabawy i poznawania STM32 chciałem odpalić I2C na przerwaniach/wyjątkach a potem dodać jeszcze do tego DMA.
A biblioteki jakoś mi nie podchodzą (masa poznawania funkcji, dokumentacja do nich itp.) już wolę przeczytać RM i ustawiać wszystko na rejestrach, chociaż wiem co dokładnie robię :) ale fakt na początku bardziej upierdliwe jest niż skorzystanie z gotowca.

Awatar użytkownika
squeez
User
User
Posty: 211
Rejestracja: czwartek 04 lut 2016, 10:13

Re: STM32F103 problem z odpaleniem I2C

Postautor: squeez » środa 06 lip 2016, 02:40

Debuger to nieocenione narzędzie :)

Ile to ja się namęczyłem nad tym a problem bardzo prozaiczny, funkcja inicjująca OLED-a przygotowywała tablicę komend i wysyłała ją (wskaźnik na tą tablicę), tyle że gdy funkcja kończyła swoją pracę (tablica była lokalna) to wiadomo co się z nią działo ... obszar pamięci był nadpisywany i w przerwaniu wysyłane były śmieci, choć tak nie do końca bo kilka wartości początkowych się zgadzało co mnie mocno zmyliło :)

Kolejna spraw to dzięki debugerowi poprawnie napisałem obsługę wyjątku dla I2C.

Jak by kogoś interesowało (tak w skrócie):

Kod: Zaznacz cały

typedef struct {
   uint8_t addr;
   uint8_t *data;
   uint8_t len;
   uint8_t state;
} T_i2c;

volatile T_i2c I2C_host;

void I2C_transmit(uint8_t addr, uint8_t *data, uint8_t len)
{
   I2C_host.addr = addr;
   I2C_host.data = data;
   I2C_host.len = len;
   I2C_host.state = 1;

   I2C1->CR2 |= I2C_CR2_ITEVTEN;
   I2C1->CR1 |= I2C_CR1_START;
}

void ssd1306_init(void)
{
   static const uint8_t buff[] = {0x00, 0xFE, 0x40}; // itp.   
   I2C_transmit(SSD1306_I2C_ADDRESS, buff, (sizeof buff / sizeof *buff) );
}

void I2C1_EV_IRQHandler(void)
{
   uint16_t tsr;

   if( (I2C1->SR1 & I2C_SR1_SB) )   //EV5
   {
      tsr = I2C1->SR1;
      I2C1->DR = I2C_host.addr;
      I2C_host.state = 2;
      return;
   }

   if( (I2C1->SR1 & I2C_SR1_ADDR) )   //EV6
   {
      tsr = I2C1->SR1;
      tsr = I2C1->SR2;
      I2C1->DR = I2C_host.data[0];   //EV8_1
      I2C_host.state = 3;
      return;
   }

   if( (I2C1->SR1 & I2C_SR1_TXE) )
   {
      if( (I2C_host.len+2)-I2C_host.state != 0 )
      {
         I2C1->DR = *(I2C_host.data + (I2C_host.state - 2));
         I2C_host.state++;
      } else {
            tsr = I2C1->SR1;
            I2C1->CR1 |= I2C_CR1_STOP;
            I2C1->CR2 &= ~I2C_CR2_ITEVTEN;
            I2C_host.state = 0;
      }
   }
}


P.S. jutro pod palec idzie DMA dla I2C :)

Awatar użytkownika
squeez
User
User
Posty: 211
Rejestracja: czwartek 04 lut 2016, 10:13

Re: STM32F103 problem z odpaleniem I2C

Postautor: squeez » czwartek 07 lip 2016, 12:36

Z kronikarskiego "obowiązku" dodam że transmisja (nadawanie) I2C w przerwaniu z DMA zrobiona w sumie z DMA łatwiej niż bez bo nie trzeba obsługiwać w zdarzenia TXE, robi to za nas DMA.

Teraz poszukam jakiegoś zegarka i dopiszę odbieranie dla mastera :)
Jak naskrobię coś co będzie bardziej użytkowe to się podzielę.

Awatar użytkownika
Marcin
User
User
Posty: 309
Rejestracja: środa 09 wrz 2015, 19:30
Lokalizacja: Królewskie miasto Sandomierz

Re: STM32F103 problem z odpaleniem I2C

Postautor: Marcin » czwartek 25 sie 2016, 21:28

Również mam problem z I2C w STM32, moja platforma testowa to chińska płytka z mikrokontrolerem STM32F103RCT6 na pokładzie.
Sam zapis wydaje się że mam opanowany, problem mam natomiast z odczytem. Funkcja która powinna w założeniu odczytać N-bajtów w rzeczywistości odczytuje z układu slave N+1 bajtów. Na oscyloskopie to wygląda tak

Obrazek

Konfigurację I2C jak i portów GPIO z nim związanych użyłem taką jak mi HAL wygenerowało.

I2C programowo zrealizowałem tak:

Kod: Zaznacz cały

#include "I2CLibrary.h"
#include "stm32f1xx_hal.h"

//#include <stdio.h>
//#include <stdlib.h>

#define I2C I2C1

#define SR2         (I2C->SR2)
#define ACK         (I2C->CR1 |= I2C_CR1_ACK)
#define NOACK          (I2C->CR1 &= ~I2C_CR1_ACK)
#define START          (I2C->CR1 |= I2C_CR1_START)
#define STOP          (I2C->CR1 |= I2C_CR1_STOP)
#define POS         (I2C->CR1 |= I2C_CR1_POS)

#define EV5       (!(I2C->SR1 & I2C_SR1_SB))
#define EV6       (!(I2C->SR1 & I2C_SR1_ADDR))
#define EV7       (!(I2C->SR1 & I2C_SR1_RXNE))
#define EV8       (!(I2C->SR1 & I2C_SR1_TXE))
#define EV8_2      (!(I2C->SR1 & (I2C_SR1_TXE | I2C_SR1_BTF)))


void I2C_SendData(uint8_t addr, uint8_t* data, uint8_t len)
{
   //send slave address
   
   START;
   while(EV5);   
   I2C->DR = addr & ~(1<<0);
   
   //send data
   
   while(EV6);
   volatile uint32_t sr2 = SR2;      
   while(EV8);
   
   
   while(len)
   {
      if(len == 1)
      I2C->DR = *data++;
      len--;
   }
   
   while(EV8_2);
   STOP;
}

void I2C_ReadData(uint8_t addr, uint8_t command, uint8_t* data, uint8_t len)
{
   
   volatile uint32_t sr2;
      
   //-----send command------
   START;
   while(EV5);   
   I2C->DR = addr & ~(1<<0);
   
   while(EV6);
   sr2 = SR2;      
   while(EV8);

   I2C->DR = command;
   
   while(EV8_2);
   STOP;      
   
   //-----read data---------
   
   START;
   while(EV5);   
   I2C->DR = addr | (1<<0);
   
   while(EV6);
   sr2 = SR2;
   
   ACK;
   
   while(len)
   {   
      if(len==1)
      NOACK;
      while(EV7);
      *data++ = I2C->DR;
      
      len--;
   }
   
   STOP;

}


Przed pierwszym użyciem a po inicjalizacji włączenie I2C

Kod: Zaznacz cały

I2C1->CR1 |= I2C_CR1_PE;


Użycie w programie

Kod: Zaznacz cały

   uint8_t PromMemory[2];
   I2C_ReadData(0xEE, 0xA2, PromMemory, 2);


I nie rozumiem dlaczego po odczycie ostatniego bitu a przed wysłaniem stopu master jeszcze coś próbuje odczytać.

Może ktoś rzucić okiem na mój problem ?

Awatar użytkownika
Marcin
User
User
Posty: 309
Rejestracja: środa 09 wrz 2015, 19:30
Lokalizacja: Królewskie miasto Sandomierz

Re: STM32F103 problem z odpaleniem I2C

Postautor: Marcin » czwartek 25 sie 2016, 22:16

Na szynie nic więcej nie ma poza GY-86.

Awatar użytkownika
Antystatyczny
Geek
Geek
Posty: 1168
Rejestracja: czwartek 03 wrz 2015, 22:02

Re: STM32F103 problem z odpaleniem I2C

Postautor: Antystatyczny » czwartek 25 sie 2016, 22:23

Kluczem do rozwiązania zagadki jest:

1. Świadomość obecności bufora (a więc konieczności odczytu dwóch bajtów zamiast jednego, jak w AVR).
2. Prawidłowe posługiwanie się bitami POS i ACK w rejestrze I2Cx->CR1. Zwłaszcza bit POS jest istotny, gdyż to on decyduje, kiedy nastąpi wygenerowanie ACK lub NACK. Jeśli bit jest wyzerowany, NACK/ACK dotyczy aktualnie odbieranego bajtu (wsuwanego do rejestru). Jeśli POS jest ustawiony, wygenerowanie NACK/ACK będzie dotyczyło dopiero następnego bajtu. Bit POS, zgodnie z treścią reference manual, ma być używany wyłącznie podczas odbierania dwóch bajtów. W przypadku jednego lub trzech i więcej bajtów bit ten ma być wyzerowany.

A wracając do bufora - To normalne, że za każdym razem masz o jeden bajt za dużo do odczytu, ponieważ jeden odebrany bajt siedzi w I2Cx->DR, a kolejny w rejestrze przesuwnym. Gdy odczytasz DR, dane z rejestru przesuwnego przenoszone są automatycznie do przed chwilą opróżnionego DR. Stąd ten nadmiarowy bajt. Spróbuj obniżyć ilość odbieranych bajtów o jeden, tzn.: Chcesz odczytać 10 bajtów. Do funkcji odczytującej dane przekazujesz "len" = 10. Wewnątrz funkcji dekrementujesz "len" i tak naprawdę starasz się odczytać 9 bajtów. Efektem będzie odczyt 10 bajtów.
"The true sign of intelligence is not knowledge but imagination" Albert Einstein.


Wróć do „Programowanie STM w C/C++”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 3 gości