Strona 1 z 1

Programowe SPI proszę o sprawdzeni

: piątek 09 cze 2017, 20:30
autor: StaryAnoda
Hej

Możecie sprawdzić czy ta obsługa SPI zarówno odbiór jak i nadawanie jest poprawne ?
Czy dobrze rozumiem według tego rysunku dane są odbierane i wysyłane od najbardziej znaczącego do najmniej ?
Oraz czy odpowiednio próbkuję dane na odpowiednim zboczu.
Test.png


Kod: Zaznacz cały

uint8_t SPI_Read_and_Write(uint8_t byte)
{
   uint8_t cnt = 0x80, Read_Byte = 0,i = 0;

   DIGITAL_IO_SetOutputLow(&CSB);
   DIGITAL_IO_SetOutputLow(&SCL);

   while(cnt)
   {
      if(byte & cnt)
      {
         DIGITAL_IO_SetOutputHigh(&SDA);
      }
      else
      {
         DIGITAL_IO_SetOutputLow(&SDA);
      }
      DIGITAL_IO_SetOutputHigh(&SCL);
      for(I = 100; I; I--)
      {
      }
      DIGITAL_IO_SetOutputLow(&SCL);
      cnt >>=1;
   }

   for (i = 0; i < 8; i++)
   {
      DIGITAL_IO_SetOutputHigh(&SCL);
      if(DIGITAL_IO_GetInput(&SDO))
      {
         Read_Byte |= 0x01 << i;
      }
      DIGITAL_IO_SetOutputLow(&SCL);
   }
   DIGITAL_IO_SetOutputHigh(&CSB);

   return Read_Byte;
}


Pytam ponieważ próbuję skomunikować się z czujnikiem ale z niewiadomych powodów nie mogę wolę sie upewnić.

Re: Programowe SPI proszę o sprawdzeni

: piątek 09 cze 2017, 21:01
autor: Antystatyczny
Potencjalny problem widzę tu:

Kod: Zaznacz cały

Read_Byte |= 0x01 << i;


Do zmiennej Read_Byte wpisujesz tak naprawdę 0x02, a pewnie wolałbyś wpisać 0x01, a następnie całość przesunąć w lewo o jedno miejsce. Proponuję taki kod:

Kod: Zaznacz cały

Read_Byte |= 0x01;
Read_Byte <<= 1;

Re: Programowe SPI proszę o sprawdzeni

: piątek 09 cze 2017, 21:13
autor: StaryAnoda
Ok dzięki dokonałem zmian:

Próbuję okiełznać ten czujnik:
https://cdn-shop.adafruit.com/datasheets/BST-BME280_DS001-10.pdf

Mój kod wygląda następująco:

Kod: Zaznacz cały

while(1U)
   {
      Send_String("BMP280 ID NUMBER: ");
      Send_Int(SPI_Read_And_Write(0xD0));
      Send_String("\r\n");
      for(I = 1000000; I; I--)
      {
      }
   }

uint8_t SPI_Read_And_Write(uint8_t Byte)
{
   uint8_t Cnt = 0x80, Read_Byte = 0, I = 0, A = 0;

   DIGITAL_IO_SetOutputLow(&CSB);
   DIGITAL_IO_SetOutputLow(&SCL);

   while(Cnt)
   {
      if(Byte & Cnt)
      {
         DIGITAL_IO_SetOutputHigh(&SDA);
      }
      else
      {
         DIGITAL_IO_SetOutputLow(&SDA);
      }
      DIGITAL_IO_SetOutputHigh(&SCL);
      for(I = 10; I; I--)
      {
      }
      DIGITAL_IO_SetOutputLow(&SCL);
      Cnt >>=1;
   }

   for (A = 0; A < 8; A++)
   {
      DIGITAL_IO_SetOutputHigh(&SCL);

      for(I = 10; I; I--)
      {
      }
      if(DIGITAL_IO_GetInput(&SDO))
      {
         Read_Byte |= 0x01;
         Read_Byte <<= 1;
      }
      DIGITAL_IO_SetOutputLow(&SCL);
   }
   DIGITAL_IO_SetOutputHigh(&CSB);

   return Read_Byte;
}


Próbuję odczytać ID i otrzymuje 6.
Skąd mam wiedzieć jaki jest rzeczywiście adres tego układu.
0x60 to adres po resecie.

Re: Programowe SPI proszę o sprawdzeni

: piątek 09 cze 2017, 21:15
autor: Antystatyczny
Wygląda na to, że czytasz odwrotnie. 0x60 to 0b0110 0000, a Ty odczytujesz 0x06, czyli 0b0000 0110. Dokładna odwrotność...

Re: Programowe SPI proszę o sprawdzeni

: piątek 09 cze 2017, 22:04
autor: xor
Próbuję odczytać ID i otrzymuje 6.
Skąd mam wiedzieć jaki jest rzeczywiście adres tego układu.
0x60 to adres po resecie.


To nie jest adres tylko identyfikator układu, czy raczej typu czujnika. Jest zawsze ten sam.

Ja mam uwagę, która możliwe, ale niekoniecznie odnosi się do uzyskanego wyniku.
Zdaje się, że próbujesz zastosować tryb "11", ale nie jestem pewien, czy go faktycznie ustawiasz (uwielbiam analizować fragmenty programu wyrwane z całości :roll: ). Być może za pierwszym obrotem pętli jest to ustawione, ale za drugim i kolejnych wydaje mi się możliwym, że nie, albowiem po wyjściu z funkcji rspi_ead_and_write pozostawiasz SCL jako LOW, a jak mówi pismo święte na stronie 32: "The automatic selection between mode ‘00’ and ‘11’ is determined by the value of SCK after the CSB falling edge." a na łobrasku na następnej stronie wyraźnie widać, że SCL po opadającym zboczu CSB w tym trybie jest HIGH.

Re: Programowe SPI proszę o sprawdzeni

: piątek 09 cze 2017, 22:14
autor: Antystatyczny
Przeanalizowałem diagram czasowy i wydaje mi się, że taka forma będzie poprawna:

Kod: Zaznacz cały

uint8_t SPI_Read_And_Write(uint8_t Byte)
{
   uint8_t Cnt = 0x80, Read_Byte = 0;

   DIGITAL_IO_SetOutputLow(&CSB);
   

   while(Cnt)
   {
      Read_Byte <<= 1;

      DIGITAL_IO_SetOutputLow(&SCL);
      if(Byte & Cnt)
      {
         DIGITAL_IO_SetOutputHigh(&SDA);
      }
      else
      {
         DIGITAL_IO_SetOutputLow(&SDA);
      }
      
      if(DIGITAL_IO_GetInput(&SDO))
      {
         Read_Byte |= 0x01;
      }      

      DIGITAL_IO_SetOutputHigh(&SCL);//slave reads bit at rising edge
      
            Cnt >>=1;
   }
   DIGITAL_IO_SetOutputHigh(&CSB);

   return Read_Byte;
}


Re: Programowe SPI proszę o sprawdzeni

: sobota 10 cze 2017, 10:59
autor: StaryAnoda
Ok pytań ciąg dalszy:

Chcę używać trybu CPOL = CPHA = '1'

Zgodnie z tym rysunkiem:

Test.png


Według tego rysunku próbkowanie jest ustawione na zboczę opadające.
xor przed pętlą główną ustawiłem SCK na HIGH.

Mój kod wygląda następująco:

Kod: Zaznacz cały

/*
 * main.c
 *
 *  Created on: 2017 Jun 09 12:18:56
 *  Author: StaryKatoda
 */




#include <DAVE.h>                 //Declarations from DAVE Code Generation (includes SFR declaration)
#include <stdio.h>

/**

 * @brief main() - Application entry point
 *
 * <b>Details of function</b><br>
 * This routine is the application entry point. It is invoked by the device startup code. It is responsible for
 * invoking the APP initialization dispatcher routine - DAVE_Init() and hosting the place-holder for user application
 * code.
 */

uint32_t I;

void Send_Char(char B);
void Send_String(char * String);
void Send_Int(int Value);

uint8_t SPI_Read_And_Write(uint8_t Byte);


int main(void)
{
   DAVE_STATUS_t status;

   status = DAVE_Init();           /* Initialization of DAVE APPs  */
   DIGITAL_IO_SetOutputHigh(&SCL);
   if(status != DAVE_STATUS_SUCCESS)
   {
      /* Placeholder for error handler code. The while loop below can be replaced with an user error handler. */
      XMC_DEBUG("DAVE APPs initialization failed\n");

      while(1U)
      {

      }

   }

   /* Placeholder for user application code. The while loop below can be replaced with user application code. */
   while(1U)
   {

      Send_String("BMP280 ID NUMBER: ");
      Send_Int(SPI_Read_And_Write(0xD0));
      Send_String("\r\n");
      Send_String("Temp_msb value: ");
      Send_Int(SPI_Read_And_Write(0xFA));
      Send_String("\r\n");



      for(I = 1000000; I; I--)
      {
      }
      DIGITAL_IO_SetOutputHigh(&LED_0);
      DIGITAL_IO_SetOutputLow(&LED_1);
      for(I = 1000000; I; I--)
      {
      }
      DIGITAL_IO_SetOutputLow(&LED_0);
      DIGITAL_IO_SetOutputHigh(&LED_1);
   }
}

void Send_Char(char B)
{
   UART_Transmit(&UART_0, &B, 1);
}


void Send_String(char * String)
{
   while(*String)Send_Char(*String++);
}

void Send_Int(int Value)
{
   char Bufor[50];
   sprintf(Bufor, "%i", Value);
   Send_String(Bufor);
}

uint8_t SPI_Read_And_Write(uint8_t Byte)
{
   uint8_t Cnt = 0x80, Read_Byte = 0, I = 0, A = 0;

   DIGITAL_IO_SetOutputLow(&CSB);

   while(Cnt)
   {
      DIGITAL_IO_SetOutputHigh(&SCL);
      if(Byte & Cnt)
      {
         DIGITAL_IO_SetOutputHigh(&SDA);
      }
      else
      {
         DIGITAL_IO_SetOutputLow(&SDA);
      }
      DIGITAL_IO_SetOutputLow(&SCL);
      Cnt >>=1;
   }

   for (A = 0; A < 8; A++)
   {
      DIGITAL_IO_SetOutputHigh(&SCL);
      if(DIGITAL_IO_GetInput(&SDO))
      {
         Read_Byte |= 0x01;
         Read_Byte <<= 1;
      }
      DIGITAL_IO_SetOutputLow(&SCL);
   }
   DIGITAL_IO_SetOutputHigh(&SCL);
   DIGITAL_IO_SetOutputHigh(&CSB);

   return Read_Byte;
}


Analizator stanów logicznych ustawiłem w taki sposób:

Test2.png


I tutaj mam pytanie dlaczego program ustawia przy próbkowaniu zbocze narastające a nie opadające
(Jest tu jakaś nieścisłość chyba. W nocie CPOL = CPHA = '1' próbkuję na opadającym)

Test3.png


I tak widać, że Nadawanie jest chyba w porządku od strony mikrokontrolera, odbieranie zawodzi co widać tutaj:

Test4.png

Re: Programowe SPI proszę o sprawdzeni

: sobota 10 cze 2017, 11:08
autor: xor
Proponuję wywalić sterowanie CSB poza funkcję SPI_Read_and_Write co umożliwi transmisje blokowe a jest to w trybie NORMAL nie tylko porządane ale wręcz niezbędne. Zresztą w transmisji "pojedynczej" mieszanie CSB miedzy adresem a zapisem/odczytem danej może powodować błędy (chyba).
To uwagi do funkcji Antystatycznego, bo to co ty robisz z tą funkcją IMHO kwalifikuje się do lekkiego naprostowania (ale to później bo teraz muszę wyjść)

Re: Programowe SPI proszę o sprawdzeni

: sobota 10 cze 2017, 13:36
autor: StaryAnoda
Hejka

Xor nic to nie dało, dalej takie same objawy.
W sensie wyciągniecie pinu CSB poza funkcję.

Re: Programowe SPI proszę o sprawdzeni

: sobota 10 cze 2017, 17:58
autor: xor
I tutaj mam pytanie dlaczego program ustawia przy próbkowaniu zbocze narastające a nie opadające
(Jest tu jakaś nieścisłość chyba. W nocie CPOL = CPHA = '1' próbkuję na opadającym)


W tym trybie ustawianie jest na "leading edge", próbkowanie na "trailing edge", ale zauważ, że w trybie nieaktywnym zegar jest HIGH, a więc "leading edge" to zbocze opadające, a "trailing" to rosnące.
Uwaga na marginesie: W drugim trybie tego czujnika "00" ustawianie jest na "trailing" próbkowanie na "leading", zegar w stanie idle jest LOW, a więc próbkowanie też będzie na zboczu rosnącym.

Wracając do programu: Niepotrzebnie gmerasz a funkcji spi_read_write. Funkcja ma za zadanie wysłać i jednocześnie odczytać jeden bajt. Prosta funkcja z jasno zdefiniowanym, łatwym do zrozumienia działaniem. Koniec, kropka. Jej kod wygląda dobrze, nawet analiza gołym okiem, bez testowania wskazuje, że prawdopodobnie będzie działać bezbłędnie. Dodawanie do niej dalszych funkcji jest niecelowe, komplikuje ją, naraża na trudne do wyłapania błędy.
Dalszy kod można konstruować na bazie tej funkcji, a mógłby wyglądać tak:

Kod: Zaznacz cały

#define ID_REG 0xD0

int main()
{
   uint8_t byte;

   ...
   
   //ustawienie trybu "11" (automagicznie przez czujnik)
   DIGITAL_IO_SetOutputHigh(&SCL);
   //aktywacja magistrali
   DIGITAL_IO_SetOutputLow(&CSB);
   //transmisja adresu rejestru
   (void)SPI_Read_And_Write(ID_REG);
   //odczytanie id z czujnika
   byte = SPI_Read_And_Write(0);
   //funkcja SPI_Read_And_Write pozostawia SCL w stanie HIGH więc następny wiersz niepotrzebny
   //DIGITAL_IO_SetOutputHigh(&SCL);
   //dezaktywacja magistrali
   DIGITAL_IO_SetOutputHigh(&CSB);
   
   //dalej wyświetlenie wartości byte
   ...
   
}

uint8_t SPI_Read_And_Write(uint8_t Byte)
{
   uint8_t Cnt = 0x80, Read_Byte = 0;


   while(Cnt)
   {
      Read_Byte <<= 1;

      DIGITAL_IO_SetOutputLow(&SCL);
      if(Byte & Cnt)
      {
         DIGITAL_IO_SetOutputHigh(&SDA);
      }
      else
      {
         DIGITAL_IO_SetOutputLow(&SDA);
      }
     
      if(DIGITAL_IO_GetInput(&SDO))
      {
         Read_Byte |= 0x01;
      }     

      DIGITAL_IO_SetOutputHigh(&SCL);//slave reads bit at rising edge
     
            Cnt >>=1;
   }

   return Read_Byte;
}


Pomijam tu konieczność ustawiania lub zerowania najstarszego bitu adresu rejestru, bo w tym przypadku, przypadkowo bit jest ustawiony jak należy.

Re: Programowe SPI proszę o sprawdzeni

: sobota 10 cze 2017, 21:14
autor: StaryAnoda
Ok

Dzięki za pomoc, odebrałem poprawny identyfikator urządzenia.

Re: Programowe SPI proszę o sprawdzeni

: niedziela 11 cze 2017, 17:04
autor: StaryAnoda
Dobra teraz chciałem się zapytać czy dobrze odbieram tą temperaturę:

Tutaj wykrywam podłączony czujnik:

Kod: Zaznacz cały

   DIGITAL_IO_SetOutputHigh(&SCL);
   DIGITAL_IO_SetOutputLow(&CSB);
   SPI_Read_And_Write(0xD0);

   if(SPI_Read_And_Write(0) == 0x60)
   {
      Send_String(" Znaleziono BME280!!! ");
   }
   else
   {
      Send_String(" Nie znaleziono BME280!!! ");
   }
   DIGITAL_IO_SetOutputHigh(&CSB);


Tutaj ustawiam w rejestrze ctrl_meas bity 7 i 5 (czyli oversampling *16) oraz bity 1 i 0 (czyli normal mode)

Kod: Zaznacz cały

   DIGITAL_IO_SetOutputHigh(&SCL);
   DIGITAL_IO_SetOutputLow(&CSB);
   SPI_Read_And_Write(0b01110100); // 0xF4
   SPI_Read_And_Write(0b10100011); // 0xA3
   DIGITAL_IO_SetOutputHigh(&CSB);


Tutaj odbieram dane Compensation parameter storage:
Zgodnie z tabelą:
Tsessss.png


Kod: Zaznacz cały

uint16_t dig_t1;
int16_t dig_t2;
int16_t dig_t3;

DIGITAL_IO_SetOutputHigh(&SCL);
      DIGITAL_IO_SetOutputLow(&CSB);
      SPI_Read_And_Write(0b10001001);
      dig_t1 = SPI_Read_And_Write(0);
      dig_t1 = dig_t1 << 8;
      DIGITAL_IO_SetOutputHigh(&CSB);

      DIGITAL_IO_SetOutputHigh(&SCL);
      DIGITAL_IO_SetOutputLow(&CSB);
      SPI_Read_And_Write(0b10001000);
      dig_t1 = dig_t1 |SPI_Read_And_Write(0);
      DIGITAL_IO_SetOutputHigh(&CSB);
      //
      DIGITAL_IO_SetOutputHigh(&SCL);
      DIGITAL_IO_SetOutputLow(&CSB);
      SPI_Read_And_Write(0b10001011);
      dig_t2 = SPI_Read_And_Write(0 );
      dig_t2 = dig_t2 << 8;
      DIGITAL_IO_SetOutputHigh(&CSB);

      DIGITAL_IO_SetOutputHigh(&SCL);
      DIGITAL_IO_SetOutputLow(&CSB);
      SPI_Read_And_Write(0b10001010);
      dig_t2 = dig_t2 |SPI_Read_And_Write(0);
      DIGITAL_IO_SetOutputHigh(&CSB);
      //
      DIGITAL_IO_SetOutputHigh(&SCL);
      DIGITAL_IO_SetOutputLow(&CSB);
      SPI_Read_And_Write(0b10001101);
      dig_t3 = SPI_Read_And_Write(0 );
      dig_t3 = dig_t3 << 8;
      DIGITAL_IO_SetOutputHigh(&CSB);

      DIGITAL_IO_SetOutputHigh(&SCL);
      DIGITAL_IO_SetOutputLow(&CSB);
      SPI_Read_And_Write(0b10001100);
      dig_t3 = dig_t3 |SPI_Read_And_Write(0);
      DIGITAL_IO_SetOutputHigh(&CSB);


Tutaj odbieram 3 bajty zawierające temperaturę :
memory.png


Kod: Zaznacz cały

      uint8_t MSB, LSB,XLSB;
      // Read MSB
      DIGITAL_IO_SetOutputHigh(&SCL);
      DIGITAL_IO_SetOutputLow(&CSB);
      SPI_Read_And_Write(0xFA);
      for(I = 1000; I; I--)
      {
      }
      MSB = SPI_Read_And_Write(0);
      DIGITAL_IO_SetOutputHigh(&CSB);

      // Read LSB
      DIGITAL_IO_SetOutputHigh(&SCL);
      DIGITAL_IO_SetOutputLow(&CSB);
      SPI_Read_And_Write(0xFB);
      for(I = 1000; I; I--)
      {
      }
      LSB = SPI_Read_And_Write(0);
      DIGITAL_IO_SetOutputHigh(&CSB);

      // Read XLSB
      DIGITAL_IO_SetOutputHigh(&SCL);
      DIGITAL_IO_SetOutputLow(&CSB);

      SPI_Read_And_Write(0xFC);
      for(I = 1000; I; I--)
      {
      }
      XLSB = SPI_Read_And_Write(0);
      DIGITAL_IO_SetOutputHigh(&CSB);


Tutaj mam pytanie odnośnie konwersji tych trzech bajtów do jednej zmiennej

Kod: Zaznacz cały

int32_t Temp;
Temp = (int32_t)( ( ( (int32_t) MSB <<16 ) | ( (int32_t)LSB <<8 ) | ((int32_t) XLSB ) ) >> 4 );


Czy to przesunięci w prawo o 4 jest potrzebne czy nie ?

Tutaj funkcja zaczerpnięta z noty katalogowej:

ffffffffffffffffffff.png


Kod: Zaznacz cały

int32_t t_fine;
int32_t bmp280_compensate_T_int32(int32_t  adc_T)
{
   int32_t var1, var2, T;
   var1  = ((((adc_T>>3) - ((int32_t)dig_t1 <<1))) * ((int32_t)dig_t2)) >> 11;

   var2  = (((((adc_T>>4) - ((int32_t)dig_t1)) *
         ((adc_T>>4) - ((int32_t)dig_t1))) >> 12) *
         ((int32_t)dig_t3)) >> 14;
   t_fine = var1 + var2;
   T = (t_fine * 5 + 128) >> 8;
   return T;
}


Tutaj wynik całego programu:

Czy macie jakieś uwagi ?
Czy dobrze interpretuję że temperatura wynosi 25.26 St C.

Terminal.png

Re: Programowe SPI proszę o sprawdzeni

: niedziela 11 cze 2017, 18:39
autor: xor
Mam cztery uwagi:
1. Te bloki powinny być zamknięte w funkcjach (nie wiem, może są ale tego nie widać w listingach)
2. Nie stosuj tzw. magic numbers. Zamiast

Kod: Zaznacz cały

   SPI_Read_And_Write(0b01110100); // 0xF4
   SPI_Read_And_Write(0b10100011); // 0xA3

wpisz

Kod: Zaznacz cały

   //gdzieś w pliku .h albo w .c w bloku różnych definicji   
   #define CTRL_MEAS_REG   0xF4
   #define TEMP_OVS_16   ((0b101)<<5)
   #define NORMAL_MODE   (0b11)
   
   //.....
   
   SPI_Read_And_Write(CTRL_MEAS_REG);
   SPI_Read_And_Write(TEMP_OVS_16 + NORMAL_MODE);


Oczywiście przy SPI trzeba pamiętać o bicie R/W (Ty to zrobiłeś ręczno nożnie), proponuję utworzyć odpowiednią funkcję (albo makro) żeby nie zaprzątać sobie głowy czy wyzerować czy ustawić bit. Wtedy pierwsze wywołanie SPI_Read_And_Write może wyglądać np. tak:

Kod: Zaznacz cały

SPI_Read_And_Write(spi_write(CTRL_MEAS_REG));


a funkcje np. tak

Kod: Zaznacz cały

   uint8_t spi_write(uint8_t address)
   {
      return address & 0x7f;
   }

   uint8_t spi_read(uint8_t address)
   {
      return address | 0x80;
   }


3. Źle odczytujesz rejestry danych. W trybie NORMAL trzeba je odczytywać jako blok, nie po jednym. Odczytywanie po jednym rejestrze może prowadzić do błędów, jeżeli konwersja zakończy się pomiędzy odczytami (a w trybie NORMAL konwersja wykonuje się automatycznie co ustalony czas). Wtedy z części rejestrów ma się dane z poprzedniej konwersji a z części z bieżącej. Przy odczycie blokowym jest zagwarantowana spójność danych. Jest to opisane w datasheecie.
Dane korekcyjne też odczytujesz po jednym, to nie jest błąd bo dane są niezmienne, ale to niepotrzebnie spowalnia i komplikuje program -> też można odczytać blokiem.
A więc potrzebujesz funkcji blokowego odczytu danych (blokowy zapis też mógłby się przydać, ale to nie jest krytyczne) np. takiej:

Kod: Zaznacz cały

#define DUMMY 0

void spi_read_block(uint8_t *buffer, uint8_t address, uint8_t len)
{
   DIGITAL_IO_SetOutputHigh(&SCL);
   DIGITAL_IO_SetOutputLow(&CSB);
   SPI_Read_And_Write(spi_read(address));
   while(len--)
      *buffer++ = SPI_Read_And_Write(DUMMY);
   DIGITAL_IO_SetOutputHigh(&CSB);
}


wywołanie

Kod: Zaznacz cały

   #define TEMP_REG   0xFA
   #define TEMP_DATA_LEN   3
   uint8_t buffer[TEMP_DATA_LEN];   //po wyjściu z funkcji zawiera kolejno temp_msb, temp_lsb, temp_xlsb

   spi_read_block(buffer, TEMP_REG, TEMP_DATA_LEN);   //odczyt nieskompensowanej temperatury



Co do prawidłowości wyliczeń się nie wypowiadam, bo po to bym nie musiał sobie tym zaprzątać głowy producent czujnika przygotował odpowiedni driver ;-)

Re: Programowe SPI proszę o sprawdzeni

: niedziela 11 cze 2017, 22:34
autor: StaryAnoda
Wielkie dzięki kolego

Jutro naniosę poprawki.

Re: Programowe SPI proszę o sprawdzeni

: poniedziałek 12 cze 2017, 08:21
autor: xor
Tutaj mam pytanie odnośnie konwersji tych trzech bajtów do jednej zmiennej

Kod: Zaznacz cały

int32_t Temp;
Temp = (int32_t)( ( ( (int32_t) MSB <<16 ) | ( (int32_t)LSB <<8 ) | ((int32_t) XLSB ) ) >> 4 );



Czy to przesunięci w prawo o 4 jest potrzebne czy nie ?


Tak, jest potrzebne albowiem w XLSB wartość jest przechowywana w 4 starszych bitach, na 4 młodszych bitach jest zawsze zero.
Coś mi jednak nie pasowało w powyższym zapisie więc zajrzałem do źródeł drivera i tam przesunięcia są trochę inne:
MSB<<12
LSB<<4
XLSB>>4
W sumie daje to liczbę 20bitową, tak jak piszą przy okazji funkcji kompensującej temperaturę.

Re: Programowe SPI proszę o sprawdzeni

: poniedziałek 12 cze 2017, 09:04
autor: xor
No to jeszcze:
Obrazek z rozmieszczeniem rejestrów jest (chyba) od czujnika BMP, wydawało mi się, że mówimy o BME, jak to w końcu jest?

Diabelnie źle czyta się kod wczytujący dane kalibracyjne. Trudno dojrzeć czy nie ma tam buga. Proponuję to uczytelnić - najpierw odczyt blokowy, potem przepisanie do globalnej struktury (albo do niezależnych zmiennych ale wtedy funkcja musiała by odwoływać się do nich nie przez parametr lecz "bezpośrednio" - tego unikamy jak ognia). Całość w odrębnej funkcji.

Kod: Zaznacz cały

struct coefficients {
   uint_16_t dig_T1;
   int16_t dig_T2;
   int16_t dig_T3;
   /dalej współczynniki dla ciśnienia i wilgotnośći
...
} coeff;

...

void read_calib_data( struct coefficients *coef)
{
   uint8_t buffer[CALIB_DATA_LEN];
   
   spi_read_block(buffer, CALIB_REG, CALIB_DATA_LEN);
   
   coef->dig_T1 = buffer[0] | buffer[1]<<8;
   // ... itd ...
}

Re: Programowe SPI proszę o sprawdzeni

: poniedziałek 12 cze 2017, 09:13
autor: Antystatyczny
Jakie są przesłanki ku temu, by unikać jak ognia wczytywania pojedynczych zmiennych? Całość i tak jest zawarta w osobnym module, a zmienne można schować korzystając ze "static". Zmienne będą o zasięgu modułu, a funkcja/funkcje korzystające z tych danych będą miały bezpośredni dostęp. Oczywiście rozumiem, że chodzi tu o dane kalibracyjne, które odczytuje się tylko raz.

Re: Programowe SPI proszę o sprawdzeni

: poniedziałek 12 cze 2017, 09:18
autor: xor
Nie ma podstaw do założenia że jest to w odrębnym module. Na razie wygląda to na jeden wielki main.
W przypadku modułu oczywiście jest tak jak mówisz.
Zresztą, nawet w module lepiej to wygląda jak jest przekazywane przez parametr. IMHO.
...ale generalnie zgadzam się z tym co jest napisane w następnych dwóch postach, 0144% zgody :-)

Re: Programowe SPI proszę o sprawdzeni

: poniedziałek 12 cze 2017, 09:21
autor: Antystatyczny
Sądzę, że wszystko jest w main jedynie na czas testów, a potem tradycyjnie trafi do osobnego modułu. Prawdę mówiąc nawet nie spojrzałem na nazwę pliku, bo skupiłem się na samych funkcjach. Oczywiście masz rację, że w obecnej formie lepiej by to wyglądało w strukturze.

Re: Programowe SPI proszę o sprawdzeni

: poniedziałek 12 cze 2017, 09:32
autor: Antystatyczny
Przekazywanie wskaźnika na strukturę z danymi kalibracyjnymi do funkcji, gdy te dane są jedynymi i nigdy nie ulegają podmianie, jest w mojej ocenie zbędnym obciążaniem rejestrów/stosu. Jak już wspomniałem wcześniej, zmienne są ukryte przed światem zewnętrznym i nie ma powodu, by dodatkowo tworzyć wskaźnik na strukturę w wywołaniu funkcji wykorzystującej dane kalibracyjne. Oczywiście dane mogą być w strukturze, to ładnie wygląda i poprawia czytelność, ale do pól można się odwoływać bezpośrednio.

Re: Programowe SPI proszę o sprawdzeni

: poniedziałek 12 cze 2017, 22:04
autor: StaryAnoda
Ok dzięki za pomoc koledzy :)

Musi mi się to wszystko przetrawić ;)
Na razie zajmuję się uporządkowaniem biblioteki, podziałem na poszczególne moduły. Za niedługo uruchomię pomiar ciśnienia i wilgotności.
Xor masz rację zrzut ekranu jest z innego czujnika nie wiem jakim prawem miałem go otwartego w przeglądarce. Cały czas mówimy o BME280.