Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Elektroda.pl
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

PC -> Nucleo -> RS485 -> STM32 Własny program do komunikacji z uC

vakacjus 14 Jun 2018 13:50 1665 21
Computer Controls
  • #1
    vakacjus
    Level 9  
    Witam,
    jestem początkującym programistą/elektronikiem. Chciałbym zbudować aplikacje która pozwoliłaby mi na wysłanie ramki crc8 bezpośrednio do STM32. Wszystko dlatego, że wysyłanie komend ciągle zmieniającym się kodem crc dla różnych czasów jest bardzo nie praktyczne + sam program ma pomóc w późniejszych projektach oraz mojemu prywatnemu rozwojowi jako programista :). Bardzo bym was prosił o kilka wskazówek z naciskiem na to jak posługiwać się takimi bibliotekami służącymi do połączeń między komputerem(aplikacją) a miktrokontrolerem najlepiej dla języka C/C++ bądź Python, jak posługiwać się ramkami CRC w aplikacji, jak się je liczy i implementuje w kodzie oraz świetnie by było jeżeli już istnieją przykłady takiego rozwiązania.

    Wszystko po to by pominąć Real Term'a i móc stworzyć jakieś przyjemne GUI =)

    O czym warto w tym przypadku poczytać? na co zwrócić uwagę. Polecacie jakąś literaturę ? Poproszę o konkrety ^^.
  • Computer Controls
  • #2
    BlueDraco
    MCUs specialist
    Najpierw wyjaśnij, co to jest "ramka CRC8".
  • #3
    vakacjus
    Level 9  
    ramka CRC czyli sposób na obliczanie sumy kontrolnej wykorzystywany w komunikacji z miktrokontrolerami, 8 utworzyło mi się z liczby wielomianu x^8+x^5+x^4+x^0 =]
  • #4
    User removed account
    User removed account  
  • #5
    Kuniarz
    Moderator of Designing
    Proszę doprecyzować co za ramki chcesz przesyłać. Samo CRC to tylko suma kontrolna obliczana na podstawie zawartości ramki.
    Ja bym zrobił mniej więcej tak:
    - jakiś bajt startu, stały dla wszystkich ramek, np. FF
    - dwa bajty długości treści ramki (komunikatu)
    - suma kontrolna CRC obliczona z wartości długości i treści
    - jakiś bajt kończący, np. F0

    Mikrokontroler, który to odbierze musi czekać na FF, następnie pobrać długość komunikatu, odczytać komunikat, obliczyć CRC i jeśli będzie zgodne z przesłanym CRC to realizować to co w ramce wysłałeś.
  • #6
    vakacjus
    Level 9  
    Wybaczcie brak precyzji spowodowany niewiedzą i wprowadzenie w błąd.

    Kuniarz wrote:
    - jakiś bajt startu, stały dla wszystkich ramek, np. FF

    1 bajt zawsze o wartości 0x3A taki stały, nastepnie urzadzenie otrzymuje bajt adresu dla peryferii, takze 0x00 0x01 0x02, to jako pierwsze bede chciał podawać do obliczeń w programie samemu pozniej dochodzi komenda (dalej zwana CMD) strerujaca urzadzeniem a nastepnie jej parametr, zależne od CMD i nie większe w bajtach niż 256 i na koniec suma kontrolna

    Przykład dla pierwszego adresu
    Code:
    Numerbajtu 1    2    3 (4 5 N+2 N+3) N+4
    
    zawartość 0x3A 0x00 CMD PARAMETR CMD CRC


    z3planety wrote:
    Czyli rozumiem że bez RealTerma nie da się programować uC? A co jak ktoś nie ma i nigdy nie miał.

    Nie zakładam, że jest to jedyne narzędzie do pracy na mikrokontrolerze, podkreśliłem, że jestem początkującym programistą więc moja styczność z softami póki co jest ograniczona.


    Kuniarz wrote:
    Mikrokontroler, który to odbierze musi czekać na FF, następnie pobrać długość komunikatu, odczytać komunikat, obliczyć CRC i jeśli będzie zgodne z przesłanym CRC to realizować to co w ramce wysłałeś.


    Wielkie dzięki, pomogłeś mi zrozumieć o co w tym chodzi. Suma liczona jest z odpowiedniego algorytmu.

    Nie zrozumcie mnie źle, nie szukam tu odpowiedzi na swój problem, lecz źródeł które mnie w jego rozwiązanie wprowadzą. Przeszukiwanie wyszukiwarek póki co skończyło się falą zaawansowanych informacji. Chciałbym dowiedzieć się jak coś takiego mogłoby wyglądać, jak dogadać się z samym mikrokontrolerem tak aby w odpowiednim języku mnie zrozumiał. Reszta przyjdzie z czasem.
  • Computer Controls
  • #7
    User removed account
    User removed account  
  • #8
    tzok
    Moderator of Cars
    W amatorskich aplikacjach nigdy nie bawiłem się w liczenie sum kontrolnych, ani tworzenie jakiś super wymyślnych formatów ramki. Twój uK ma sprzętową obsługę USART i może być widziany jako wirtualny port COM, to najprostszy sposób komunikacji z PC. Możesz sobie przesyłać bajt po bajcie, albo zdefiniować jakiś bufor, który po wypełnieniu wywołuje przerwanie obsługi. Masz też gotowe I2C (TWI), w dodatku obsługiwane sprzętowo.

    Wiem, że to nie do STM32*, ale myślę, że coś Ci to może pomóc (jeśli umiesz myśleć i chcesz się czegoś nauczyć, a nie dostać gotowca kopiuj-wklej):
    https://playground.arduino.cc/Main/InterfacingWithSoftware
    https://playground.arduino.cc/Interfacing/Processing

    * - ...w sumie to jest możliwość programowania STM32 z poziomu Arduino IDE.
  • #9
    _jta_
    Electronics specialist
    Jeśli chodzi o liczenie CRC, to
    man 3 _crc8_ccitt_update wrote:
    Optimized CRC-8-CCITT calculation.
    Polynomial: x^8 + x^2 + x + 1 (0xE0)
    The following is the equivalent functionality written in C.
    Code: c
    Log in, to see the code

    Jest to wprawdzie dla innego wielomianu CRC, ale chyba to nie problem przetłumaczyć? Wielomian jest w tym 0x07 (kompletny dawałby 0x107).

    _crc8_ccitt_update należy do pakietu avr-libc w Linux-ie Ubuntu (i pewnie również w Debian-ie i pochodnych).
  • #10
    Freddie Chopin
    MCUs specialist
    _jta_ wrote:
    Optimized CRC-8-CCITT calculation.

    Zapomnieli tylko dopisać, że "optimized for small size", bo na pewno nie zoptymalizowany pod względem wydajności czy wygody używania.

    Do generowania kodu liczącego różne CRC polecam po prostu https://pycrc.org/ . Jak ktoś chce kod który jest szybki, to wybiera algorytm "table driven" - tablica o wielkości `sizeof(crc_t) * 256`, można ją zmniejszyć stosując argument --table-idx-width, np. przy wartości 4 tablica ma tylko 16 elementów.
  • #12
    Freddie Chopin
    MCUs specialist
    _jta_ wrote:
    Oj, chyba nieuważnie przeczytałeś: zoptymalizowany kod jest w bibliotece, a ten pokazany jest tylko ilustracją - prostym sposobem uzyskania tego samego wyniku.

    Chyba raczej Ty nieuważnie przeczytałeś. Algorytm funkcji - nawet pomimo tego że jest w assemblerze:
    - dalej jest wolny, ponieważ dla każdego bajtu wykonywane jest 8 obiegów pętli,
    - dalej jest niewygodny w użytkowaniu, ponieważ funkcję trzeba wywołać dla każdego bajtu osobno.

    Jego "optymalność" polega tylko i wyłącznie na tym, że jest w assemblerze (na tym forum jest kilka takich osób które uznają, że już bardziej optymalnego kodu się nie da zrobić).
    http://svn.savannah.gnu.org/viewvc/avr-libc/t...de/util/crc16.h?revision=2398&view=markup

    Tak więc nadal polecam to co wypluwa z siebie pycrc, szczególnie w przypadku algorytmu "table driven".

    Code:
    $ pycrc --width 8 --poly 0x07 --reflect-in False --xor-in 0x00 --reflect-out False --xor-out 0x00 --generate=c --algorithm=table-driven

    Code:
    /**
    
     * \file pycrc_stdout
     * Functions and types for CRC checks.
     *
     * Generated on Thu Jul  5 11:53:44 2018,
     * by pycrc v0.9, https://pycrc.org
     * using the configuration:
     *    Width         = 8
     *    Poly          = 0x07
     *    Xor_In        = 0x00
     *    ReflectIn     = False
     *    Xor_Out       = 0x00
     *    ReflectOut    = False
     *    Algorithm     = table-driven
     *****************************************************************************/
    #include "pycrc_stdout.h"     /* include the header file generated with pycrc */
    #include <stdlib.h>
    #include <stdint.h>

    /**
     * Static table used for the table_driven implementation.
     *****************************************************************************/
    static const crc_t crc_table[256] = {
        0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d,
        0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65, 0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d,
        0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb, 0xf2, 0xf5, 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd,
        0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, 0xa8, 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd,
        0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2, 0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea,
        0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2, 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a,
        0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, 0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a,
        0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42, 0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a,
        0x89, 0x8e, 0x87, 0x80, 0x95, 0x92, 0x9b, 0x9c, 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4,
        0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec, 0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4,
        0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c, 0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44,
        0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c, 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34,
        0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, 0x76, 0x71, 0x78, 0x7f, 0x6a, 0x6d, 0x64, 0x63,
        0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b, 0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13,
        0xae, 0xa9, 0xa0, 0xa7, 0xb2, 0xb5, 0xbc, 0xbb, 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83,
        0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb, 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3
    };

    /**
     * Update the crc value with new data.
     *
     * \param crc      The current crc value.
     * \param data     Pointer to a buffer of \a data_len bytes.
     * \param data_len Number of bytes in the \a data buffer.
     * \return         The updated crc value.
     *****************************************************************************/
    crc_t crc_update(crc_t crc, const void *data, size_t data_len)
    {
        const unsigned char *d = (const unsigned char *)data;
        unsigned int tbl_idx;

        while (data_len--) {
            tbl_idx = (crc ^ *d);
            crc = (crc_table[tbl_idx]) & 0xff;

            d++;
        }
        return crc & 0xff;
    }


    Albo jak ktoś naprawdę lubi powolne algorytmy:

    Code:
    pycrc --width 8 --poly 0x07 --reflect-in False --xor-in 0x00 --reflect-out False --xor-out 0x00 --generate=c --algorithm=bit-by-bit

    Code:
    /**
    
     * \file pycrc_stdout
     * Functions and types for CRC checks.
     *
     * Generated on Thu Jul  5 11:54:52 2018,
     * by pycrc v0.9, https://pycrc.org
     * using the configuration:
     *    Width         = 8
     *    Poly          = 0x07
     *    Xor_In        = 0x00
     *    ReflectIn     = False
     *    Xor_Out       = 0x00
     *    ReflectOut    = False
     *    Algorithm     = bit-by-bit
     *****************************************************************************/
    #include "pycrc_stdout.h"     /* include the header file generated with pycrc */
    #include <stdlib.h>
    #include <stdint.h>
    #include <stdbool.h>

    /**
     * Update the crc value with new data.
     *
     * \param crc      The current crc value.
     * \param data     Pointer to a buffer of \a data_len bytes.
     * \param data_len Number of bytes in the \a data buffer.
     * \return         The updated crc value.
     *****************************************************************************/
    crc_t crc_update(crc_t crc, const void *data, size_t data_len)
    {
        const unsigned char *d = (const unsigned char *)data;
        unsigned int i;
        bool bit;
        unsigned char c;

        while (data_len--) {
            c = *d++;
            for (i = 0; i < 8; i++) {
                bit = crc & 0x80;
                crc = (crc << 1) | ((c >> (7 - i)) & 0x01);
                if (bit) {
                    crc ^= 0x07;
                }
            }
            crc &= 0xff;
        }
        return crc & 0xff;
    }


    /**
     * Calculate the final crc value.
     *
     * \param crc  The current crc value.
     * \return     The final crc value.
     *****************************************************************************/
    crc_t crc_finalize(crc_t crc)
    {
        unsigned int i;
        bool bit;

        for (i = 0; i < 8; i++) {
            bit = crc & 0x80;
            crc = (crc << 1) | 0x00;
            if (bit) {
                crc ^= 0x07;
            }
        }
        return (crc ^ 0x00) & 0xff;
    }
  • #13
    _jta_
    Electronics specialist
    dalej jest wolny, ponieważ dla każdego bajtu wykonywane jest 8 obiegów pętli

    Nie sprawdzałem wcześniej tego kodu w bibliotece - rzeczywiście, nie jest optymalny pod względem szybkości. No cóż, jak ktoś ma trochę czasu, to może podesłać szybką wersję liczenia CRC8. Wolna i tak jest potrzebna, do zainicjowania tablicy - jakkolwiek nie trzeba jej liczyć w ten sposób dla wszystkich elementów, wystarczy dla 1, 2, 4, 8, 16, 32, 64 i 128, bo resztę można korzystając z wzoru crc8tab[index1^index2]=crc8tab[index1]^crc8tab[index2]; to można sprowadzić do algorytmu inicjowania tablicy: zeruj wszystko, weź 0x80, przesuń o 1 bit i jeśli trzeba, zrób xor 0x07, zrób xor wyniku z elementami tablicy z indeksami, których bit 0 jest 1; przesuń o kolejny bit (i xor 0x07, jeśli trzeba), xor wyniku z elementami, których bit 1 jest 1; potem będzie bit 2, 3...7. W sumie 8 przebiegów pętli zewnętrznej, w każdym 256 wewnętrznej, i tam w każdym warunkowy XOR bajtu tablicy z aktualną wartością "CRC".
  • #14
    User removed account
    User removed account  
  • #16
    User removed account
    User removed account  
  • #17
    User removed account
    User removed account  
  • #20
    User removed account
    User removed account  
  • #21
    _jta_
    Electronics specialist
    STM32F030x{4,6,8,C} 'Value-line ARM ® -based 32-bit MCU with up to 256-KB Flash,
    timers, ADC, communication interfaces, 2.4-3.6 V operation'
    wrote:
    3.4 Cyclic redundancy check calculation unit (CRC) (strona 13)
    The CRC (cyclic redundancy check) calculation unit is used to get a CRC code using a
    configurable generator polynomial value and size.


    Ale to jest krótki opis, nie zawiera informacji, jak i do czego można tego używać (z wyjątkiem tego, że może być użyty do SPI). Podobnie dla STM32F103.
  • #22
    User removed account
    User removed account