Tento materiál je určen všem těm, kteří si chtějí postavit vlastní zařízení s CAN rozhraním. Pamatuji si, že když jsem před několika lety s CANem začínal, tak se mi ze všech těch bitů v tehdy používaném řadiči MCP2510 pěkně motala hlava. Před nedávnou dobou jsem si hrál s obvodem CC750, takže se tu pokusím shrnout to co o tomto obvodu znám a snad tím někomu ulehčím práci.
Obsah:
Úvod | Rozdělení CAN controllerů na kategorie. | |
Popis rozdílů mezi obvody Intel 82527 a Bosch CC750/CC770 | V čem jsou tyto obvody shodné a v čem se liší. | |
SPI interface | Popis komunikace prostřednictvím rozhraní SPI. | |
Popis registrů | Popis adresního prostoru, registrů a řídících bitů. | |
SPI prakticky | Praktická ukázka formou zdrojových kódů v jazyce C. | |
Inicializace | Praktická ukázka formou zdrojových kódů v jazyce C. | |
Komunikace | Praktická ukázka formou zdrojových kódů v jazyce C. |
Díl první: Úvod
CAN controllery (řadiče) sběrnice CAN je možno rozdělit do dvou základních skupin podle principu jejich funkce a to nezávisle na tom, zda se jedná o samostatné obvody, jádra pro hradlová pole, nebo periferie různých procesorů. První skupina obvodů obvykle obsahuje několik bufferů, nebo jeden FIFO (SJA1000) buffer, kdy buffer(y) může(mohou) obsahovat několik zpráv se stejným identifikátorem. Druhá skupina obsahuje obvykle větší množství bufferů, z nichž každý je určen pro jednu konkrétní zprávu nebo skupinu zpráv v případě implementace lokálních masek. Samozřejmě hranice mezi těmito skupinami není nijak ostrá. U mnoha obvod se dá diskutovat o tom, do které skupiny by bylo možno je zařadit.
První skupina controllerů je vhodná zejména pro různé karty pro PC, kdy potřebujeme přijímat obvykle všechny zprávy bez ohledu na identifikátor. Druhá skupina je pak určena pro cílová zařízení jako jsou různé IO karty, řídící jednotky pohonů apod. Vlastnosti obvodů první kategorie se nám mohou na první pohled zdát vhodné i pro jednoduché aplikace s nejrůznějšími jednočipy, nicméně později zjistíme že na obsluhu tohoto obvodu z jednočipu spotřebujeme příliš režie, jako například:
-
nutnost u přijaté zprávy dekódovat identifikátor v případě, že jednotka odesílá zprávy s několika ID
-
v případě že jednotka odesílá zprávy s několika identifikátory, je nutno vždy identifikátor znovu nastavit
-
nutnost kompletní obsluhy a zpracování při příjmu zprávy RTR procesorem
Obvody druhé kategorie s množstvím bufferů nám toto značně zjednodušují. K těmto obvodům patří Intel 82527 a Bosch CC750/770. Popis jejich vlastností, konfigurace a řízení bude obsahem tohoto článku.
Díl druhý: Popis rozdílů mezi obvody Intel 82527 a Bosch CC750/CC770
Obvody CC770 a AN82527 jsou pinově a softwarově shodné, liší se jen několika v AN82527 rezervovanými bity, které jsou v CC770 použity. Dále pak obvod CC770 má implementovány pro čtení čítače TEC (Transmit Error Counter) a REC (Receive Error Counter) a podporuje maskování bitů Xtd a Dir v Message 15 Mask registru.
Obvod CC750 se od AN82527 a CC770 liší takto:
- pouze jeden SPI mód
- s CPU může komunikovat pouze prostřednictvím SPI, nemá paralelní sběrnici
- nemá paralelní porty a s jejich řízením spojné bity v registrech
- nemá Clockout pin
- pouze po jednom výstupu Tx a Rx
Obvod CC750 se pak navíc liší od CC770 adresou registrů TEC a REC.
V dalším textu se primárně zaměříme na popis CC750 a budeme si uvádět rozdíly od CC770 a AN82527. Speciální vlastnosti (paralelní výstupy atd.) CC750 a AN82527 nebudu popisovat, neboť nemám s nimi praktickou zkušenost.
Díl třetí: SPI interface
Na připojení SPI rozhraní není nic zvláštního, CAN controller se chová jako slave. S masterem je propojen 4 vodiči MOSI, MISO,SPICLK a CS. CS nemusí být teoreticky použito a lze se synchronizovat pomocí registru Serial Reset Address. V dokumentaci k CC750 se píše, že CPU musí zapsat string 16 bajtů 0xFF pro navázání synchronizace. S touto funkcí bohužel nemám žádné zkušenosti.
Obvod CC750 má jen jeden mód SPI. Obvody CC770 a 82527 dovolují výběr módu SPI pomocí multifunkčních pinů AD0-AD3 takto:
AD0 (ICP) Idle Clock Polarity
|
one |
SCLK is idle high |
|
zero |
SCLK is idle low |
AD1 (CP) Clock Phase
|
one |
Je-li ICP=0 jsou data samplována na sestupné hraně. Je-li ICP=1 jsou data samplována na nástupné hraně. |
|
zero |
Je-li ICP=0 jsou data samplována na nástupné hraně. Je-li ICP=1 jsou data samplována na sestupné hraně. |
AD2 (CSAS) Chip Select Active State
|
one |
Aktivní stav CS je log. high. |
|
zero |
Aktivní stav CS je log. low |
AD3 (STE) Synchronization Transmission Enable
Povolení generování synchronizačních bajtů AAh a 55h při přenosu adresy a řídícího slova.
Vlastní přenos na SPI může být tvořen blokem bajtů o maximální délce 17. První bajt je adresa odkud budeme číst nebo zapisovat. Druhý bajt je řídícím slovem. Zbylých až 15 bajtů jsou data zapisovaná od zadané adresy směrem nahoru. Řídící slovo (Serial Control Byte) má tuto strukturu:
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Dir | Sync | SDLC |
Pro čtení z CAN controlleru má Dir hodnotu 0, pro zápis pak 1. Sync musí být vždy nastaveno na 000. SDLC (Serial Data Length Code) pak udává délku dat, jsou povoleny hodnoty 1-15. V okamžiku kdy CPU odesílá adresu, CAN controller vrací zpět hodnotu AAh, při odesílání řídícího slova pak controller odesílá 55h. Tyto hodnoty by měl CPU kontrolovat. V případě že nejsou tyto hodnoty obdrženy, je nutno provést restart SPI interface zápisem dat FFh na SPI. FFh je adresa registru Serial Reset Address.
Zde si dovolím malé odbočení. Pokud jste již někdo pracoval s CAN controllery od firmy Microchip (MCP2510/2515), jistě se vám bude zdát tento protokol na SPI trochu chudý. Controllery Microcipu mají interface na SPI daleko bohatější. Nedovolují jen prostý zápis a čtení, ale podporují celou skupinu mnohdy velice praktických příkazů:
Read | Čtení |
Write | Zápis |
Reset | Softwarový reset |
RTS - Request To Send | Odeslání dat v zadaném bufferu |
Read Status | Rychlé zjištění stavu o tom zda byla přijata nějaká zpráva, zda bylo dokončeno odeslání zprávy |
BitModify | Modifikace bitů v registru pomocí masky (nepotřebujeme znát stav ostatních bitů) |
Read RX buffer (pouze MCP2515) |
Čtení zadaného RX bufferu (ušetříme přenos 1 bajtu na rozdíl od Read) |
Load TX buffer (pouze MCP2515) |
Zápis do zadaného TX bufferu (ušetříme přenos 1 bajtu na rozdíl od Write) |
RX Status (pouze MCP2515) |
Rychle zjištění podrobnějšího stavu RX bufferů |
Maximální rychlost SPI rozhraní je 8Mhz. Minimální pak 0.5 MHz. Pro porovnání MCP2510 dovoluje maximální rychlost 5MHz, MCP2515 pak 10MHz.
Díl čtvrtý: Popis registrů
Adresní prostor obvodů má velikost 256 bajtů. Následující obrázek uvádí strukturu pro obvod CC750. Odlišnosti u AN82527 a CC770 budou popsány vždy u konkrétní adresy.
Reg CONTROL (00H)CONTROL (00H)
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Název | res | CCE | res | Silent | EIE | SIE | IE | Init |
Atributy | rw | rw | r | rw | rw | rw | rw | rw |
Aributy: r-jen pro čtení / w-jen pro zápis / rw-jen pro čtení
Bity označené jako res (reserved) jsou čteny jako 0 a musí být zapisovány jako 0. Po hardwarovém resetu je registr nataven na hodnotu 01H.
CCE | Change Configuration Enable |
1 | Nastavíme li tento bit na 1, můžeme zapisovat do Bit Timing registrů. Bit Init by měl být taktéž nastaven na 1. |
0 | Zápis do Bit Timing registrů není možný. |
Silent | Silent Mode |
1 | Silent mód je aktivní. V tomto režimu může obvod přijímat platné datové a rtr zprávy. Nemůže však zprávy odesílat, odesílá pouze recesivní bity. |
0 | Normální mód. |
EIE | Error Interrupt Enable |
1 | Povolení EIE. Ten je generován při nastavení příznaků BOff (Bus Off) nebo Warn ve Status registru, tzn. při abnormálním výskytu chyb při přenosu zpráv. |
0 | EIE zakázán. Interrupt není generován |
SIE | Status Change Interrupt Enable |
1 | Povoleni SIE. Interupt je generován při změně ve Status registru, tzn. je li detekována chyba na sběrnici (LEC) nebo při nastavení příznaků WakeUp (opuštění PowerDown nebo Sleep módu), TxOK (zpráva byla odeslána), RxOK(přijata zpráva). Pokud je SIE povolen, musíme počítat s tím, že při příjmu nebo odeslání zprávy dostaneme dvě přerušení na jednu zprávu. |
0 | Zápis do Bit Timing registrů není možný. |
IE | Interrupt Output Enable |
1 | Interrupt pin je povolen. |
0 | Interrupt pin je zakázán. |
Init | Initialization |
1 | Softwarová inicializace povolena. Tento bit je nastaven z CPU pokud chceme nastavovat konfigurační registry CC750 nebo pokud obvod přejde do stavu Bus Off. Všechny přenosy na CAN nebo z CANu jsou zastaveny. Výstup Tx je v recesivním stavu. Init by neměl být nastavován v pracovním režimu, pokud provádíme modifikaci dat pro odeslání některého Message objektu (tzn. CPUUpd bit je nastaven). |
0 | Softwarová inicializace zakázána. |
Reg STATUS (01H)STATUS (01H)
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Název | BOff | Warn | WakeUp | RxOK | TxOK | LEC | ||
Atributy | r | r | r | rw | rw | rw |
Hodnota po HW resetu je 00H.
BOff | Bus Off |
1 | Obvod je ve stavu Bus Off, tzn. TEC (Treansmit Error Counter) dosáhl hranice 256. V tomto stavu nemohou byt odesílány nebo přijímány. Je nastaven bit Init v Control registru. Z tohoto stavu se dostaneme resetem Init bitu. Poté jsou vynulovány registy TEC a REC, CC750 napočítá 128 paketů 11 nepřetržitých recesivních bitů na CAN sběrnici a Bus Off stav je opuštěn. |
0 | Obvod není ve stavu Bus Off. |
Warn | Warning Status |
1 | Tento bit je nastaven pokud některý čítač TEC (Transmit Error Counter) nebo REC (Receive Error Counter) dosáhne hodnoty 96. |
0 | Obvod není ve stavu Bus Off. |
WakeUp | Wake Up Status |
1 | Bit je nastaven po opuštění Power Down nebo Sleep módu. Nastavením bitu Sleep v registru CPU Interface přejde CC750 do Sleep módu. Dokud je obvod ve Sleep módu, je tento bit nastaven na 0. Ten je opuštěn pokud je detekována aktivita na CAN sběrnici nebo pokud CPU nastaví bit Sleep na 0. Následně je nastaven tento bit. Bit WakeUp je resetován čtením Status registru. |
0 | Nenastala podmínka pro nastavení. |
RxOK | Receive Message Successfully |
1 | Tento bit je nastavován z CC750, resetován pak pouze z CPU. Bit je nastaven do 1 v případě, že od posledního nastavení do 0 z CPU byla přijata nepoškozená zpráva. |
0 | Nebyla přijata žádná zpráva. |
TxOK | Transmit Message Successfully |
1 | Tento bit je nastavován z CC750, resetován pak pouze z CPU. Bit je nastaven do 1 v případě, že od posledního nastavení do 0 z CPU byla bezchybně odeslána zpráva. |
0 | Nebyla odeslána žádná zpráva. |
LEC | Last Error Code |
0 | No error |
1 | Stuff Error - Detekována sekvence více než 5 stejných bitů na sběrnici |
2 | Form Error - Chyba v pevné části formátu zprávy (viz. CAN specifikace). |
3 | Acknowledgment Error - Odeslaná zpráva z tohoto zařízení nebyla potvrzena. |
4 | Bit 1 Error - Při odeslání zprávy generoval CC750 recesivní bit ale detekoval na sběrnici bit dominantní. |
5 | Bit 0 Error - Při odeslání zprávy generoval CC750 dominantní bit ale detekoval na sběrnici bit recesivní. |
6 | CRC Error - Chyba dat detekovaná z CRC kódu. |
7 | Unused |
Toto pole udává první chybu, která nastala při přenosu zprávy na CAN sběrnici. Jestliže byla zpráva přenesena (přijata/odeslána) bezchybně, je toto pole nastaveno na 0. Kód 7 může být použit pro kontrolu, zda nastal update dat.
Reg CPU INTERFACE (02H)CPU INTERFACE (02H)
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Název | OscSt | res | DMC | PwD | Sleep | res | res | res |
Atributy | r | r | rw | rw | rw | r | r | r |
Defaultní hodnota registru po HW resetu je 20h. Rezervované bity mají hodnotu při čtení 0.
OscSt | Oscillator Stopped |
1 | Oscilátor je zastaven |
0 | Oscilátor běží. |
Jestliže dá CPU požadavek na Power Down nebo Sleep v okamžiku, kdy probíhá odeslání nebo příjem zprávy, je pozastaveno vypnutí oscilátoru dokud tento přenos není ukončen. CC750 indikuje Power Down nebo Sleep mód nastavením tohoto bitu.
DMC | Divide Memory Clock |
1 | Memory clock MCLK je roven SCLK/2. |
0 | Memory clock MCLK je roven SCLK/2. |
PwD | Sleep | Function |
0 | 0 | Power down mód ani Sleep mód nejsou aktivní. |
0 | 1 | Sleep mód je aktivní. |
1 | X | Power Down mód není aktivní. |
Reg: RESERVED (03H)RESERVED (03H)
U obvodů CC750/CC770/AN82527 nemá žádnou funkci.
Reg: RESERVED (04H,05H)
HIGH SPEED READ - CC770/AN82527
U CC750 nemá žádnou funkci. U CC770 se používá v případech, kdy CPU nemůže čekat na ukončení čtení z pomalých registrů CC770 (Message Object) tzn.není možno použít signály READY a DSACK0. První čtení dáme požadavek na čtení, vrácená data jsou však neplatné. Druhé čtení z High Speed Read Registru nám vrátí požadovaná data. K podrobnějšímu studiu doporučuji datasheety těchto obvodů.
Reg: GLOBAL MASK - STANDARD (06H, 07H)GLOBAL MASK - STANDARD (06H, 07H)
Bity - 06H | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Název | Msk28 | Msk27 | Msk26 | Msk25 | Msk24 | Msk23 | Msk22 | Msk21 |
Atributy | rw | rw | rw | rw | rw | rw | rw | rw |
Bit - 07H | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Název | Msk20 | Msk19 | Msk18 | res | res | res | res | res |
Atributy | rw | rw | rw | r | r | r | r | r |
Bity nejsou ovlivněny HW resetem. Rezervované bity jsou čteny jako 1. Maska je aplikována na zprávy se standardním 11 bitovým identifikátorem.
Je-li bit v masce nastaven na 1, musí bit v příchozí zprávě odpovídat bitu v identifikátoru zprávy Message Objectu. Pokud je bit v masce nastaven na 0, je na této pozici akceptována jakákoliv hodnota bitu. Pokud je příchozí zpráva typu RTR a je použita globální maska, má zpráva s odpovědí identifikátor příslušného vyhovujícího Message Objektu. To znamená že RTR zpráva může mít jiný identifikátor než vygenerovaná odpověď s daty.
Reg: GLOBAL MASK - EXTENDED (08H, 09H, 0AH, 0BH)GLOBAL MASK - EXTENDED (08H, 09H, 0AH, 0BH)
Bity - 08H | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Název | Msk28 | Msk27 | Msk26 | Msk25 | Msk24 | Msk23 | Msk22 | Msk21 |
Atributy | rw | rw | rw | rw | rw | rw | rw | rw |
Bity - 09H | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Název | Msk20 | Msk19 | Msk18 | Msk17 | Msk16 | Msk15 | Msk14 | Msk13 |
Atributy |
rw | rw | rw | rw | rw | rw | rw | rw |
Bity - 0AH | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Název | Msk12 | Msk11 | Msk10 | Msk09 | Msk08 | Msk07 | Msk06 | Msk05 |
Atributy | rw | rw | rw | rw | rw | rw | rw | rw |
Bity - 0BH | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Název | Msk04 | Msk03 | Msk02 | Msk01 | Msk00 | res | res | res |
Atributy | rw | rw | rw | rw | rw | r | r | r |
Bity nejsou ovlivněny HW resetem. Rezervované bity jsou čteny jako 0. Maska je aplikována na zprávy s rozšířeným 29 bitovým identifikátorem.
Je-li bit v masce nastaven na 1, musí bit v příchozí zprávě odpovídat bitu v identifikátoru zprávy Message Objectu. Pokud je bit v masce nastaven na 0, je na této pozici akceptována jakákoliv hodnota bitu. Pokud je příchozí zpráva typu RTR a je použita globální maska, má zpráva s odpovědí identifikátor příslušného vyhovujícího Message Objektu. To znamená že RTR zpráva může mít jiný identifikátor než vygenerovaná odpověď s daty.
Reg: MESSAGE 15 MASK (0CH, 0DH, 0EH, 0FH)MESSAGE 15 MASK (0CH, 0DH, 0EH, 0FH)
Bity - 0CH | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Název | Msk28 | Msk27 | Msk26 | Msk25 | Msk24 | Msk23 | Msk22 | Msk21 |
Atributy | rw | rw | rw | rw | rw | rw | rw | rw |
Bity - 0DH | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Název | Msk20 | Msk19 | Msk18 | Msk17 | Msk16 | Msk15 | Msk14 | Msk13 |
Atributy |
rw | rw | rw | rw | rw | rw | rw | rw |
Bity - 0EH | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Název | Msk12 | Msk11 | Msk10 | Msk09 | Msk08 | Msk07 | Msk06 | Msk05 |
Atributy | rw | rw | rw | rw | rw | rw | rw | rw |
Bity - 0FH | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Název | Msk04 | Msk03 | Msk02 | Msk01 | Msk00 | MDir | MXtd | res |
Atributy | rw | rw | rw | rw | rw | rw | rw | r |
Tato maska je určena pouze pro Message Object 15. Princip filtrování je schodný s globální maskou. Navíc obsahuje bity MDir a MXtd.
MXtd | Mask Extended Bit |
1 | V příchozí zprávě se kontroluje zda souhlasí nastavení bitu Xtd v Message Objectu 15 |
0 | Jsou přijímány standardní i rozšířené zprávy. |
Stejně tak funguje i bit MDir. Object 15 je sice určen pouze pro příjem zpráv, takže na první pohled se nám může zdát, že nastavení směru nemá význam. Nicméně nesmíme zapomenout na to že i Message Object určený pro odesílání zpráv kontroluje zda příchozí zpráva není typu RTR a nesouhlasí identifikátor a nemá náhodou odeslat odpověď. To znamená že tu například můžeme vymaskovat příjem pouze zpráv RTR.
Reg: RECEIVE ERROR COUNTER (1FH)RECEIVE ERROR COUNTER (1FH)
Bity | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Název | RP | REC6 | REC5 | REC4 | REC3 | REC2 | REC1 | REC0 |
Atributy | r | r | r | r | r | r | r | r |
RP | Receive Error Pasive |
1 | REC je nad hranicí Error Passive úrovně, která je definována v CAN specifikaci. |
0 | REC je pod hranicí Error Passive úrovně. |
REC6-0 udávají aktuální hodnotu čítače REC (Receive Error Counter). Hodnoty jsou 127-0.
Reg: TRANSMIT ERROR COUNTER (2FH)TRANSMIT ERROR COUNTER (2FH)
Obsahuje 8-bitovou hodnotu TEC (Transimit Error Counter).
Reg: BIT TIMING 0 (3FH)BIT TIMING 0 (3FH)
Bity | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Název | SJW1 | SJW0 | BRP5 | BRP4 | BRP3 | BRP2 | BRP1 | BRP0 |
Atributy | rw | rw | rw | rw | rw | rw | rw | rw |
Defaultní hodnota po HW resetu je 00h. SJW ( (Re) Synchronization Jump Width) udává maximální počet časových kvant o které může být kratší nebo delší než resynchronizace.Možné hodnoty jsou 0-3. BRP (Baud Rate Prescaler) slouží k nastavení délky časového kvanta: Tq = Tsclk*(BRP+1).
K výpočtu nastavení hodnot BIT TIMING registrů doporučuji použít nějaký program nebo webovou stránku, která výpočet nastavení udělá za nás. Protože tyto registry jsou shodné s obvodem 82527, můžete výpočet provést například zde.
Reg: BIT TIMING 1 (4FH)BIT TIMING 1 (4FH)
Bity | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Název | Spl | TSeg22 | TSeg21 | TSeg20 | TSeg13 | TSeg12 | TSeg11 | TSeg10 |
Atributy | rw | rw | rw | rw | rw | rw | rw | rw |
Defaultní hodnota po HW resetu je 00h.
Spl | Sampling Mode |
1 | Každý bit je samplován 3x. |
0 | Bit je samplován 1x vzužívá se při vyšších přenosových rychlostech. . |
TSeg2x | Time Segment 2 |
0-7 | Délka časového segmentu po samplovacím bodu. |
TSeg1x | Time Segment 1 |
0-15 | Délka časového segmentu před samplovacím bodem. |
K výpočtu nastavení hodnot BIT TIMING registrů doporučuji použít nějaký program nebo webovou stránku, která výpočet nastavení udělá za nás. Protože tyto registry jsou shodné s obvodem 82527, můžete výpočet provést například zde.
Reg: INTERRUPT (5FH) INTERRUPT (5FH)
Bity | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Název | IntId | |||||||
Atributy | r |
Defaultní hodnota po H resetu je 00h. Registr je určen pouze pro čtení. Hodnota registru udává zdroj přerušení. Pokud žádný interrupt nečeká na vyřízení, je hodnota tohoto registru 0. Jestliže je nastaven bit SIE v Control registru a CC750 updatoval Status registr, je v tomto registru Interrupt hodnota 1.
Zdroj přerušení | Hodnota Interrupt registru |
None | 00h |
Status Register | 01h |
Message Object 15 | 02h |
Message Object 1 | 03h |
Message Object 2 | 04h |
Message Object 3 | 05h |
Message Object 4 | 06h |
Message Object 5 | 07h |
Message Object 6 | 08h |
Message Object 7 | 09h |
Message Object 8 | 0Ah |
Message Object 9 | 0Bh |
Message Object 10 | 0Ch |
Message Object 11 | 0Dh |
Message Object 12 | 0Eh |
Message Object 13 | 0Fh |
Message Object 14 | 10h |
SERIAL RESET ADDRESS (FFH)
MESSAGE 1 (10H-1EH), MESSAGE 2 (20H-2EH)
MESSAGE 3 (30H-3EH), MESSAGE 4 (40H-4EH)
MESSAGE 5 (50H-5EH), MESSAGE 6 (60H-6EH)
MESSAGE 7 (70H-7EH), MESSAGE 8 (80H-8EH)
MESSAGE 9 (90H-9EH), MESSAGE 10 (A0H-AEH)
MESSAGE 11 (B0H-BEH), MESSAGE 12 (C0H-CEH)
MESSAGE 13 (D0H-DEH), MESSAGE 14 (E0H-EEH)
Každý Message Object je reprezentován pole dat s touto strukturou:
Address | Function |
Base Address + 0 | Control 0 |
Base Address + 1 | Control 1 |
Base Address + 2 | Arbitration 0 |
Base Address + 3 | Arbitration 1 |
Base Address + 4 | Arbitration 2 |
Base Address + 5 | Arbitration 3 |
Base Address + 6 | Configuration |
Base Address + 7 | Data 0 |
Base Address + 8 | Data 1 |
Base Address + 9 | Data 2 |
Base Address + 10 | Data 3 |
Base Address + 11 | Data 4 |
Base Address + 12 | Data 5 |
Base Address + 13 | Data 6 |
Base Address + 14 | Data 7 |
Control 0
Bity | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Název | MsgVal | TxIE | RxIE | IntPnd | ||||
Atributy | rw | rw | rw | rw |
Control 1
Bity | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Název | RmtPnd | TxRqst | MsgLst/CPUUpd | NewData | ||||
Atributy | rw | rw | rw | rw |
Každý bit v tomto registru je uložen dvakrát. To umožňuje modifikovat bity registru bez znalosti hodnot ostatních bitech registru. Pro modifikaci těchto bitových párů se používají tyto párové variant:
Direction | MSB | LSB | Příkaz |
Write | 0 | 0 | Kombinace není nastavena |
0 | 1 | Reset (nastavení na 0) | |
1 | 0 | Set (Nastavení na 1) | |
1 | 1 | Neměnit - bit zůstane nezměněn. | |
Read | 0 | 1 | Reset (bit má hodnotu 0) |
1 | 0 | Set (bit má hodnotu 1) |
V případě že například do registru Control 0 je zapsána hodnota 0b01111011, dává první párová dvojice bitů 01 příkaz k nastavení MsgVal na 0, druhá a čtvrtá párová dvojice obsahuje bity 11 a říká že nastavení TxIE a IntPnd má zůstat nezměněna. Třetí párová dvojice 10 pak dává požadavek na nastavení RxIE na 1.
MsgVal | Message Valid |
1 | Příslušný Message Object je platný, tzn. že CC750 může k tomuto objektu přistupovat. Například v případě že měníme identifikátor zprávy, musíme nejprve příslušný objekt zneplatnit. |
0 | Message Objct není platný. |
TxIE | Transmit Interrupt Enable |
1 | Povolení přerušení (interruptu) při příchodu nové platné zprávy do tohoto Message Objectu. CPU musí tento bit smazat. |
0 | Přerušení je zakázáno. |
RxIE | Receive Interrupt Enable |
1 | Povolení přerušení po úspěšném odeslání z tohoto Message Objectu. CPU musí tento bit smazat. |
0 | Přerušení je zakázáno. |
lntPnd | Interupt Pending |
1 | Bit je nastaven po úspěšném příjmu nebo odeslání zprávy. |
0 | Od posledního smazání tohoto bitu nenastala žádná událost vyvolávající přerušení. |
RmtPnd | Remote Request Pending |
1 | Je požadováno odeslání tohoto objektu přijetím RTR zprávy. Bit má význam pouze při nastavení příslušného objektu pro odesílání zpráv (direction = transmit). Bit je smazán z CC750 automaticky po odeslání zprávy. |
0 | Žádný RTR požadavek nebyl přijat. |
TxRqst | Tranmit Request |
1 | Požadavek na odeslání tohoto objektu na sběrnici je požadován a nebyl ještě dokončen. Nastavením tohoto bitu je odeslána datová zpráva pokud je tento objekt nakonfigurován pro odeslání, v případě že je konfigurován pro příjem, je odeslána RTR zpráva. Bit je nastavován z CPU při požadavku na odeslání nebo při vyřizování požadavku RTR je-li objekt nakonfigurován pro odeslání. Je-li objekt konfigurován pro příjem, je nastavením tohoto bitu odeslán požadavek RTR. Bit je smazán z CC750. |
0 | Objekt nečeká na odeslání. |
MsgLst | Message Lost - objekt konfigurován pro příjem z CAN sběrnice |
1 | Bit je nastaven pokud byla přijata nová zpráva a CPU ještě nestihl obsloužit předchozí. |
0 | Žádná zpráva nebyla ztracena. |
CPUUpd | CPU Updating - objekt konfigurován pro odesílání |
1 | Objekt nesmí být odeslán - CPU nastavením indikuje provádění změny dat. |
0 | Objekt může být odeslán. |
NewData | New Data |
1 | CPU nebo CC750 zapsal data do datové části zprávy. |
0 | Žádná nová data od posledního smazání bitu z CPU. |
Jestliže je objekt nastaven pro příjem, nastavuje CC750 bit NewData v okamžiku, kdy je přijata do tohoto objektu nová zpráva. CPU by měl tento bit vymazat před vyčtením této nové zprávy a po jejím vyčtení tento bit zkontrolovat, zda nebyl znovu nastaven a data nemohla být v průběhu čtení přepsána. Message object 15 obsahuje je na rozdíl od objektů 1 až 14 tvořen dvěma sadami registrů. Druhá shadow (stínová) sada slouží jako vyrovnávací paměť, čímž nám snižuje pravděpodobnost ztráty dat v případě, kdy by CPU nestihl předešlá data zpracovat. Zároveň nám tato sada zaručuje, že data ve viditelné sadě nebudou přepsána, tzn. že nemusíme kontrolovat bit NewData. Naopak, u tohoto objektu provádíme čtení dat tak, že nejprve přečteme data a až následně resetujeme NewData a RmtPnd. Reset NewData a RmtPnd před resetováním IntPnd má za následek, že signál interrupt zůstane aktivní.
Pokud je objekt nastaven pro odesílání zpráv, je nutno bit CPUUpd nastavit na 1 před započetím změny dat zprávy. Po nastavení dat je tento bit opět nastaven z CPU na 0. Tímto mechanismem je zabezpečeno, že zpráva nemůže být odeslána například RTR požadavkem v okamžiku, kdy provádíme změnu dat. Odeslání zprávy se provede nastavením NewData a TxRqst na 1.
Jestliže čeká na odeslání několik objektů, je nejprve odeslána zpráva s nižším indexem objektu bez ohledu na prioritu identifikátoru (Při přístupu na CAN sběrnici má větší prioritu zpráva nižším identifikátorem).
Arbitration 0
Bity | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Název | ID28 | ID27 | ID26 | ID25 | ID24 | ID23 | ID22 | ID21 |
Atributy | rw | rw | rw | rw | rw | rw | rw | rw |
Arbitration 1
Bity | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Název | ID20 | ID19 | ID18 | ID17 | ID16 | ID15 | ID14 | ID13 |
Atributy | rw | rw | rw | rw | rw | rw | rw | rw |
Arbitration 2
Bity | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Název | ID12 | ID11 | ID10 | ID09 | ID08 | ID07 | ID06 | ID05 |
Atributy | rw | rw | rw | rw | rw | rw | rw | rw |
Arbitration 3
Bity | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Název | ID04 | ID03 | ID02 | ID01 | ID00 | reserved | ||
Atributy | rw | rw | rw | rw | rw | r |
Registry Arbitration 0-3 jsou obsahují identifikátor zprávy. V případě standardního identifikátoru je jeho 11 bitů uloženo v ID18-ID28.
Configuration Register
Bity | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Název | DLC | Dir | Xtd | reserved | ||||
Atributy | rw | rw | rw | r |
DLC | Data Length Code |
0-8 | Počet datových bajtů ve zprávě. Platné hodnoty jsou 0-8 |
Dir | Direction |
1 | Direction = transmit. Objekt je určen pro odeslání. Je li nastaven TxRqst je objekt s daty odeslán. |
0 | Direction = receive. Objekt je určen pro příjem. Je li nastaven TxRqst, je odeslána žádost o data (RTR). Je li zachycena zpráva jejíž identifikátor vyhovuje tomuto objektu, je zpráva do tohoto objektu uložena. |
Xtd | Extended Identifier |
1 | Message object používá rozšířený 29 bitový identifikátor. |
0 | Message object používá standardní 11 bitový identifikátor. Nastavením tohoto bitu na 0 jsou bity 0-17 v registrech Arbitration nastaveny na 0. |
Po přijetí zprávy z CANu do tohoto objektu jsou bity identifikátoru, které jsou maskou nastaveny jako nekontrolované (bit v masce je nastaven na 0) nastaveny podle přijaté zprávy.
Reg: MESSAGE 15 (F0H-FEH) MESSAGE 15 (F0H-FEH)
Tento objekt je určen pouze pro příjem zpráv. Bity TxRqst, TxIE a CPUUpd nemají význam. Objekt může aktuálně obsahovat až 2 zprávy, neboť obsahuje druhou sadu registrů do které je zapsána zpráva pokud není předchozí ještě z CPU zpracována. Tento objekt můžeme nastavit pro příjem standardních nebo rozšířených zpráv bite Xtd. Tento bit může být maskován a jsou přijímány oba typy zpráv.
RESERVED (6FH), RESERVED (7FH)
RESERVED (8FH), RESERVED (9FH)
RESERVED (AFH), RESERVED (BFH)
RESERVED (CFH), RESERVED (DFH)
RESERVED (EFH)
Registry nejsou využity.
Díl pátý: SPI prakticky
Předchozí díly obsahovaly zatím jen teorii a data z datasheetu přeložené do češtiny. V tomto okamžiku se však již dostáváme k praktické realizaci. Protože však existuje spousta CPU ke kterým můžeme CAN controller CC750 připojit, pokusím se uváděné zdrojové kódy psát bez ohledu na cílový procesor. Proto vynechám například vlastní implementaci komunikace po SPI a budu používat obecné funkce SPI_Read a SPI_Write. Rovněž obsluha přerušení bude obsahovat pouze kód bezprostředně týkající se CC750 a ne obsluhu implementačně závislou jako je například mazání nejrůznějších "Flagů" v CPU. Může se ovšem stát, že část kódu bude přecejen ovlivněna mojí cílovou platformou (PIC 16F877 & překladač HiTech PICC v.7.8x).
Programování aplikací s jednočipy obvykle začíná dvěma kroky. Za prvé je třeba inicilizovat vstupy/výstupy a periferie. Za druhé je vhodné vytvořit si sadu maker typu eCAN_CS - signál enable CS obvodu CC750 do log 0, dCAN_CS - signál disable CS obvodu CC750 do log 1 a dále bitových masek pro nastavení registrů. První krok vynechám, je implementačně závislý a přejdu k druhému.
V mém případě jsem si nachystal tato makra a definice:
//--------------------------------------------------------------- // e - Enable // d - Disable // i - Input // o - Output #define oCAN_CS RD0 // Signal CS na port D, bit 0 #define iCAN_INT RB0 // Vstupni signal, INTERRUPT #define eCAN_CS oCAN_CS = 0 // Enable CS #define eCAN_RST oCAN_RST = 0 // Enable RESET
//---------------------------------------------------------------
#define SPI_READ_CMD 0x00
#define SPI_SYNC1 0xAA // Kontrola synchronizace (adresa) #define SPI_SYNC2 0x55 // Kontrola synchronizace (cmd)
//---------------------------------------------------------------
#define CC750_CONTROL 0x00 #define CC750_MSG1 0x10 //---------------------------------------------------------------
#define CC750_TRANSMIT_BUFFER 0b00000000 // 0x00 #define CC750_DLC0 0b00000000 // 0x00 |
Poznámka: Překladač HiTech PICC dovoluje zadávat čísla v binárním tvaru, rozšiřuje tak definici jazyka C. Tvar je analogický zadání tvaru šestnástkového čísla, tzn. takto 0bXXXXXXXX.
Začneme komunikací prostřednictvím sběrnice SPI. Jak již bylo zmíněno, pro zápis a čtení z SPI budeme používat funkce SPI_Read a SPI_Write. Tyto funkce je třeba implementovat v závislosti na cílovém procesoru. Jejich hlavičky jsou definovány takto:
unsigned char SPI_Read(void); void SPI_Write(unsigned char Data); |
Pokud zasíláme adresu registru, musí být přijata zpět po SPI data 0xAA, v případě že zasíláme command, musíme obdržet zpět hodnotu 0x55. Pro kontrolu těchto hodnot budeme používat dvě globální proměnné:
unsigned char SPI_sync[2] bool SPI_error = false;
Pro HiTech PICC: bit SPI_error; |
Zde následuje vlastní zdrojový kód s komentáři:
//--------------------------------------------------------------- unsigned char Data; eCAN_CS; SPI_sync[0] = SPI_Write(Address); SPI_sync[1] = SPI_Write(SPI_READ_CMD | 0x01);
if(SPI_sync[0]!=SPI_SYNC1 || SPI_sync[1]!=SPI_SYNC2) SPI_error = true;
Data = SPI_Read(); dCAN_CS; //--------------------------------------------------------------- SPI_sync[0] = SPI_Write(Address); SPI_sync[1] = SPI_Write(SPI_WRITE_CMD | 0x01); if(SPI_sync[0]!=SPI_SYNC1 || SPI_sync[1]!=SPI_SYNC2) SPI_error = true; SPI_Write(Data); dCAN_CS; return; //--------------------------------------------------------------- eCAN_CS; SPI_sync[0] = SPI_Write(Address); SPI_sync[1] = SPI_Write(SPI_READ_CMD | Length);
if(SPI_sync[0]!=SPI_SYNC1 || SPI_sync[1]!=SPI_SYNC2) SPI_error = true;
for(index=0; index<Length; index++) *Data = SPI_Read(); Data++; return; //--------------------------------------------------------------- SPI_sync[0] = SPI_Write(Address); SPI_sync[1] = SPI_Write(SPI_READ_CMD | Length);
if(SPI_sync[0]!=SPI_SYNC1 || SPI_sync[1]!=SPI_SYNC2) SPI_error = true;
for(index=0; index<Length; index++) SPI_Write(*Data); Data++; return; //--------------------------------------------------------------- unsigned char index; |
Provádět kontrolu délky dat při přenosu bloku dat považuji na jednočipech za zbytečnou, každá tato kontrola zpomaluje program. Funkci SPI_Error používáme k resynchronzaci SPI rozhraní pokud dojde k nastavení SPI_error na hodnotu true.
Díl šestý: Inicializace
V okamžiku, kdy máme hotovou komunikaci po SPI, včetně implementace funkcí SPI_Read a SPI_Write, můžeme začít pracovat s registry CAN řadiče. Pro práci s registry Control 0 a 1 jednotlivých Message objektů použijeme tyto funkce:
//--------------------------------------------------------------- // CAN_ReadMsgControl // Cteni bitoveho paru registru Control1 a Control2 Message objektu //--------------------------------------------------------------- // CAN_WriteMsgControl // Zapis do bitoveho paru registru Control1 a Control2 Message objektu void CAN_WriteMsgControl(unsigned char address, unsigned char pair, unsigned char value) |
Dále naimplemenujeme funkce pro nastavení pracovního a konfiguračního módu (registr CONTROL):
//--------------------------------------------------------------- // SetConfigMode // Prepnuti do konfiguracniho modu //--------------------------------------------------------------- void CAN_SetConfigMode(void) //--------------------------------------------------------------- // CAN_SetNormalMode // Prepnuti do pracovniho modu // (lze komunikovat prostřednictvím CAN sbernice) //--------------------------------------------------------------- void CAN_SetNormalMode(void) |
Další funkcí bude nastavení komunikační rychlosti:
//--------------------------------------------------------------- // CAN_SetBaudRate // Nastaveni komunikacni rychlosti CAN sběrnice // Parametr speed v KBaudech //--------------------------------------------------------------- void CAN_SetBaudRate(unsigned int speed) |
Následují funkce pro nastavení globální masky zpráv:
//--------------------------------------------------------------- // CAN_ConfigureGlobalMaskSt // Maska pro zpravy se standardnim (11 bitovym) identifikatorem //--------------------------------------------------------------- void CAN_ConfigureGlobalMaskSt(unsigned int mask) //--------------------------------------------------------------- // CAN_ConfigureGlobalMaskExt // Maska pro zpravy s rozsirenym (29 bitovym) identifikatorem //--------------------------------------------------------------- void CAN_ConfigureGlobalMaskExt(unsigned long mask) |
Poslední funkcí v této kapitole bude funkce pro nastavení Message objektu:
//--------------------------------------------------------------- // CAN_ConfigureBuffer // Zakladni konfigurace message objektu //--------------------------------------------------------------- void CAN_ConfigureBuffer(unsigned char buffer, unsigned char status, unsigned long identifier) // Message object is invalid // Transmit Interrupt Disable // Receive Interrupt Disable // Interrupt Pending // Remote Transfer Pending // Transmit Request // Message Lost / CPU Updating // New Data //DLC // Message object is valid |
V další kapitole si probereme podrobně jak uvedené funkce pracují a ukážeme si jak odeslat zprávu.
Díl sedmý: Komunikace
Hned na začátku začneme funkcí pro elementární odeslání zprávy na CAN. Tato funkce CAN_SendMessage má tři parametry, číslo bufferu (message objektu), ukazatel na pole dat a délku dat. Maximální délka těchto dat je limitována délkou CANovské zprávy, tj. 8 bajtů. V případě, že chceme odesílat delší data, je třeba provést fragmentaci těchto dat na bloky s tuto maximální délkou.
//--------------------------------------------------------------- // CAN_SendMessage // Odeslani zpravy na CAN void CAN_SendMessage(unsigned char buffer, unsigned char *data, unsigned char length) // New Data SPI_Write_Block(CC750_MSG1+(buffer*0x10)+7, length, data); // CPU Updating // Transmit Request |
Uvedená funkce začíná testem, zda hodnota bitového páru TxRqst v registru CONTROL_1 má hodnotu reset, tzn. 01, tedy hodnotu reset. Pokud je tato hodnota nastavena na Reset, nečeká buffer na odeslání a je tedy možno jej použít. Nastavení CPU Updating zabezpečuje, že nemůže dojít k modifikaci obsahu objektu přijetím zprávy z CANu v průběhu jeho modifikace z CPU. Pomocí funkce SPI_Write_Block jsou zapsány datové bajty zprávy. Transmit Request pak nastavuje požadavek na odeslání dat.
//---------------------------------------------------------------
// CAN_GetMessage
// Cteni zpravy
//---------------------------------------------------------------
unsigned char CAN_GetMessage(unsigned char buffer, unsigned char *data)
{
unsigned char tmp;
// New Data = 1 ?
//if(CAN_ReadMsgControl(CC750_MSG1+(buffer*0x10)+1, 0)==0) return 0;
tmp = CAN_ReadMsgControl(CC750_MSG1+(buffer*0x10)+1, 0);
// New Data = 0
CAN_WriteMsgControl(CC750_MSG1+(buffer*0x10)+1, 0, 0);
SPI_Read_Block(CC750_MSG1+(buffer*0x10)+7, 8, data);
if(tmp==0) return 0;
return buffer;
}