• Rezultati Niso Bili Najdeni

RAZVOJ PROGRAMSKE KODENAPRAVE ZA NADZOR PLOVILA

N/A
N/A
Protected

Academic year: 2022

Share "RAZVOJ PROGRAMSKE KODENAPRAVE ZA NADZOR PLOVILA"

Copied!
48
0
0

Celotno besedilo

(1)

Univerza v Ljubljani

Fakulteta za elektrotehniko

LUKA VRHOVNIK

RAZVOJ PROGRAMSKE KODE NAPRAVE ZA NADZOR PLOVILA

Diplomsko delo

Visokošolski strokovni študijski program prve stopnje Aplikativna elektrotehnika

Mentor: doc. dr. Matija Pirc

Ljubljana, 2021

(2)
(3)

3

Zahvala

Najprej bi se rad zahvalil mentorju Matiji Pircu, za pomoč pri izdelavi diplomske naloge. Velika zahvala pa gre tudi podjetju Sentinel Marine solutions in predvsem mojemu mentorju v podjetju Maticu Hermanu in tudi ostalim, ki so mi omogočili, da sem lahko pisanje diplomske naloge združil z delom v podjetju.

Najlepša hvala!

(4)

4 Vsebina

Vsebina

1 Uvod 11

2 Razvojno okolje 13

3 Struktura programa in operacijski sistem 15

3.1 Operacijski sistem FreeRTOS ... 16

3.2 Opravilo commands_task ... 17

3.3 Opravilo BLE_task ... 18

3.4 Opravilo modem_task ... 19

3.5 Opravilo gps_task ... 20

3.6 Opravilo data_task ... 23

3.7 Opravilo can_task ... 24

3.8 Opravilo meas_task ... 27

3.9 Opravilo accel_task ... 28

3.10 Opravilo usbd_task ... 32

3.11 Opravilo logger_task ... 32

3.12 Varnostni časovnik ... 32

4 Komunikacija s periferijo 35 4.1 I2C komunikacija z razširjevalcem GPIO pinov ... 35

4.2 USB konzola ... 38

4.3 UART komunikacija z modemom ... 38

4.4 Komunikacija z integriranim vezjem za CAN vodilo ... 42

5 Zaključek 45

Literatura 47

(5)

5

Seznam uporabljenih simbolov

UART - universal asynchronous receiver-transmitter – univerzalna asinhrona serijska sprejemno-oddajna komunikacija

Tx - Transmit – prenos Rx - Receive – sprejem

GPIO – general purpose input/output – univerzalni priključki, ki se lahku uporabijo kot vhod ali izhod

SPI – Serial Peripheral interface – sinhronsko serijsko vodilo za prenos podatkov med elektronskimi napravami

I2C - Inter-Integrated Circuit – sinhrono serijsko vodilo, ki za prenos uporablja samo 2 liniji.

CAN - Controller Area Network – protokol, razvit za avtomobilsko industrijo za komunikacijo med sistemi v vozilu.

BLE – Bluetooth low energy – brezžičen protokol komuniciranja za uporabo na kratki oddaljenosti in z nizko porabo energije

USB – Universal serial bus – univerzalno serijsko vodilo namenjeno predvsem priklopu naprav na računalnik

LTE – Long term evolution – četrta generacija mobilnih omrežij, ki omogoča višje hitrosti prenosa kot predhodniki

Baud rate – hitrost prenosa, največkrat uporabljena v povezavi s serijskimi vodili, pomeni največje število prenesenih bitov v eni sekindi

GPS – global positioning system – sistem pozicioniranja naprav s pomočjo satelitov NMEA0183 – standard komuniciranja navtičnih elektronskih naprav

(6)

6 Seznam uporabljenih simbolov

RAM - Random-access memory – naključno dostopen spomin, torej spomin do katerega lahko dostopamo v vsakem trenutku in hitrost branja ni odvisna od lokacije predhodnega branja.

V – volts – enota za merjenje električne napetosti Hz – Hertz – enota za merjenje frekvence

g – gravitacijski pospešek

0x – simbol označevanja števil v šestnajstiškem številčnem sistemu

KbPS – kilo bytes per second – enota, ki se uporablja za merjenje hitrosti prenosa podatkov

(7)

Povzetek 7

Povzetek

Cilj diplomskega dela je bil razvoj programske opreme za napravo za sledenje plovilom. Potrebno je razviti napravo, ki bo zmožna preko mobilne povezave na strežnik javljati informacije o svoji poziciji ter o stanju senzorjev, ki so priključeni na napravo (senzorji napetosti baterije, digitalni senzorji, senzorji temperature itd.).

Poseben poudarek je tudi na zanesljivosti programske opreme, saj se naprava uporablja na plovilih zasebnih lastnikov; okvara bi pomenila veliko nezadovoljstvo uporabnika in velike stroške zamenjave.

Projekt obsega implementacijo operacijskega sistema FreeRTOS na mikrokrmilnik Nordic NRF52840 in komunikacijo z ostalimi napravami v vezju.

Predstavljen je način komunikacije s pospeškometrom LSM6DSM in razširjevalnikom GPIO pinov preko I2C vodila. Predstavljena je implementacija komunikacije z modemom quectel EC21-E in GPS modulom quectel L96 preko povezave UART in komunikacija z integriranim vezjem MCP2515 za CAN vodilo, preko povezave SPI.

Opisan je proces pridobivanja in obdelave podatkov pridobljenih iz vseh zgoraj omenjenih povezav, kot tudi proces nastavitve in krmiljenja le-teh.

Projekt zaradi svoje obsežnosti še ni v celoti zaključen, vendar za zdaj kaže, da bo izdelek zadostil vsem zahtevam, ki so bile zadane ob začetku. Naprava je cenejša od predhodne, deluje na novejšem LTE omrežju in je modularna. Vse glavne funkcije naprave že delujejo, potrebuje pa še nekaj izboljšav, da bo izdelek primeren za prodajo na trgu in predvsem še nekaj testiranja zanesljivosti.

Ključne besede: sledenje plovilom, operacijski sistem FreeRTOS, quectel EC21-E

(8)
(9)

Abstract

The aim of the presented work was to develop the firmware for the boat monitoring device that will be able to report information about its position and the status of sensors connected to the device (battery voltage sensors, digital sensors, temperature sensors, etc.) via a mobile connection to a server. Special emphasis is placed on the reliability of the software, as the device is used on privately owned vessels and any failure would mean great user dissatisfaction and high replacement costs.

The project includes the implementation of the FreeRTOS operating system on the Nordic NRF52840 microcontroller and communication with other devices in the circuit. The method of communication with the LSM6DSM accelerometer and the GPIO pin expander via I2C bus is presented. The implementation of communication with the quectel EC21-E modem and the quectel L96 GPS module via a UART connection and communication with the CAN chip MCP2515 via an SPI connection are presented. The process of obtaining and processing data obtained from all the above-mentioned connections is described, as well as the process of setting up and controlling those devices.

Due to the extent of the project it is not yet fully completed, but for now it seems that the product will meet all the requirements set at the beginning. All the main functions of the device are already working, but it still needs some improvements and thorough testing to make the product suitable for sale on the market.

Key words: vessel tracking, FreeRTOS operating system, quectel EC21-E

(10)
(11)

11

1 Uvod

Z izdelavo diplomske naloge sem začel v podjetju Sentinel Marine solutions.

Vizija podjetja je ustvariti pametna plovila, ki v realnem času omogočajo sledenje, nadzor nad sistemi in upravljanje s sistemi na plovilu. Podjetje je vodilno na svojem področju. Izdelki se prodajajo po vsem svetu, večinoma se vgrajujejo v čolne in jadrnice od dolžine 6 do 20 metrov. Do sedaj so bili največji kupci podjetja, ki oddajajo svoja plovila v najem, saj je za njihov posel nadzor nad plovilom zelo pomemben. V zadnjem času pa so naše izdelke v svoja plovila začeli serijsko vgrajevati nekateri izdelovalci čolnov in jadrnic. Prav zato se proizvodnja zelo hitro povečuje - v prejšnjih letih je bilo prodanih med 500 in 1000 naprav na leto, za prihodnja leta pa se načrtuje povečanje prodajnih številk za vsaj 10-krat. V zadnjem času se pojavlja vedno več konkurence na trgu (Garmin, Siren marine, idr.), zato se je v podjetju pojavila potreba po izdelavi nove verzije naprave Boat monitor. V primerjavi s trenutno napravo mora biti nova predvsem cenejša (zaradi povečanja proizvodnje se vsak privarčevan evro na napravi veliko pozna). Naprava bo modularna, kar pomeni, da bo pri novi napravi več različic, ki bodo prilagojene potrebam posameznih plovil. Naši glavni prednosti pred konkurenco sta nizka cena in dolgoletne izkušnje s tega področja. Zahteve za napravo in aplikacijo, s katero uporabnik upravlja z napravo, smo dobili od samih uporabnikov, zato smo lahko zadostili vsem njihovim potrebam.

Cilj moje naloge pri podjetju je, da s pomočjo mentorja v podjetju napišem programsko opremo za novo napravo. Projekt je zelo obsežen, saj ima glavni mikrokrmilnik na napravi veliko nalog, ki jih mora sočasno izvajati, na primer:

• Komunikacija z modemom preko UARTA, flash pomnilnik v modemu se uporablja tudi za hranjenje podatkov,

• Komunikacija s CANbus integriranim vezjem (angl. Integrated Circuit – IC) preko SPI povezave,

• Komunikacija z razširjevalnikom GPIO pinov preko I2C povezave,

• Pridobivanje podatkov iz pospeškometra preko I2C povezave,

• Pridobivanje podatkov iz GPS modula preko UARTa,

(12)

12 1 Uvod

• Komunikacija s pomožnim procesorjem (msp430 FR2422) preko SPI povezave.

• USB povezava, ki se uporablja za konzolo,

• BLE komunikacija z različnimi zunanjimi BLE senzorji,

• Branje analognih in digitalnih vrednosti na GPIO pinih,

• Procesiranje vseh pridobljenih podatkov ter shranjevanje.

Najvišja prioriteta pri pisanju kode je zanesljivost njenega izvajanja, saj so naprave nameščene v plovilih praktično na vseh koncih sveta, odpoved naprave zaradi programske opreme bi zato povzročilo veliko gospodarsko škodo za podjetje.

(13)

13

2 Razvojno okolje

Programska oprema se je razvijala na mikrokrmilniku nordic NRF52840. Ta vsebuje 1MB pomnilnika flash in 256KB RAM pomnilnika, podpira bluetooth 5 protokol in ima 48 vhodno-izhodnih pinov med drugim podpira UART, SPI, I2C in USB 2.0 komunikacije, zato je pravi za naš projekt.

Za razvoj programske opreme se je uporabljal program »Segger Embeded studio for ARM«. Koda pa se je pisala v programskem jeziku C.

Slika 2.1: razvojno okolje Segger embedded Studio [4]

Segger Embeded studio omogoča pisanje kode, prevajanje kode (compiler), simulacijo in razhroščevanje v istem programu. Za povezavo s sistemom, ki se razvija, se potrebuje samo J-link povezavo. Delovanje celotnega sistema dobro prikazuje spodnja slika:

(14)

14 Error! Use the Home tab to apply Naslov 1 to the text that you want to appear here.

Slika 2.2: prikaz razvojnega okolja segger embedded studio [5]

(15)

15

3 Struktura programa in operacijski sistem

Naprava Boat monitor mora istočasno opravljati več nalog, ki so že predstavljene v uvodu. Zato je program razdeljen v več opravil. Za razvrščanje opravil in komunikacijo med njimi pa je uporabljen operacijski sistem FreeRTOS.

FreeRTOS je bil izbran ker:

• Ima zelo veliko bazo uporabnikov, velika skupnost pomeni, da se ob pojavu problema le-ta hitreje razreši, saj obstaja velika verjetnost, da je na enak problem naletel že kateri od ostalih uporabnikov.

• Je brezplačen za uporabo.

• Uporabljajo ga tudi nekateri naši partnerji, to pomeni, da je deljenje programske kode veliko lažje.

• Je zelo enostaven za uporabo, vse njegove funkcije so dobro opisane, ponekod pa so podani tudi primeri njihove uporabe.

• Glede porabe programskega spomina sicer FreeRTOS ni najboljši. boljši je na primer CoOs, vendar še vedno zasede dovolj malo prostora za naše potrebe.

Nobeden od ostalih operacijskih sistemov na trgu ni tako dobro ustrezal zahtevam. Od uporabe katerega izmed ostalih operacijskih sistemov nas je odvrnilo:

• Slabe izkušnje z operacijskim sistemom CoOs iz prejšnjih projektov. V primerjavi s FreeRTOS je njegova uporaba veliko bolj zapletena, imel pa je tudi kar veliko programskih napak.

• Operacijski sistem embOS je plačljiv in ne predstavlja nobene dodane vrednosti v primerjavi s FreeRTOS.

• Ostali operacijski sistemi, kot na primer Apache Mynewt so zanimivi vendar nimajo tako velike baze uporabnikov in tako dobre podpore kot FreeRTOS.

(16)

16 Error! Use the Home tab to apply Naslov 1 to the text that you want to appear here.

3.1 Operacijski sistem FreeRTOS

FreeRTOS ponuja:

• Razvrščanje opravil,

• Različne možnosti dodeljevanja delovnega spomina opravilom (vključno z možnostjo statičnega dodeljevanja spomina),

• Sisteme za usklajevanje med različnimi opravili kot so obvestila, čakalne vrste, semaforji, muteksi, medpomnilniki.

Operacijski sistem omogoča, da se različna opravila izvajajo na videz istočasno.

V resnici razvrščevalnik dodeljuje procesorski čas različnim opravilom takrat, ko ga ta potrebujejo. Razvrščevalnik razvrščuje procesorski čas glede na prioritete posameznih opravil. Če na primer opravilo z višjo prioriteto želi procesorski čas medtem, ko se izvaja opravilo z nižjo prioriteto, se le-to prekine, dokler opravilo z višjo prioriteto ne opravi svojega dela. Dodajanje opravil se izvršuje s klicem funkcije xTaskCreate. Ob klicu je potrebno podati funkcijo kjer se opravilo izvaja, ime opravila, velikost pomnilnika, ki se bo rezerviral za potrebe izvajanja opravila, parameter, ki se bo podal ob zagonu opravila, prioriteto opravila in »ročaj«, ki se potrebuje takrat, ko želimo na primer izbrisati opravilo ali pa mu spremeniti prioriteto.

Spodnja koda prikazuje kreacijo novega opravila.

error_check = xTaskCreate(commands_task, "commands_task", 1024,

NULL, 6,

commands_task_h);

if(error_check == errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY) {

APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);

}

Torej ima opravilo commands_task prioriteto 6 (najvišja možna prioriteta je 15 najnižja pa 0). Opravilu je dodeljen pomnilnik velik 4096b (1024b x 4).

Za komunikacijo med različnimi opravili in tudi med prekinitvami in opravili se uporablja čakalne liste. Novo čakalno listo se ustvari s klicem funkcije xQueueCreate, funkcija vrne »ročaj« do ustvarjene čakalne liste. Ročaj se kasneje uporablja za pisanje in branje iz čakalne liste. Ob ustvarjanju je potrebno podati še velikost posameznega objekta v čakalni listi in maksimalno število objektov, ki jih čakalna lista lahko shrani. Funkcija nato rezervira potreben medpomnilnik, kamor se shranjujejo objekti v čakalni listi.

(17)

Error! Use the Home tab to apply Naslov 2 to the text that you want to appear here. 17

UBaseType_t GPS_queue_item_count = 10;

UBaseType_t GPS_queue_item_len = sizeof(struct buffer_t);

GPS_queue = xQueueCreate( GPS_queue_item_count, GPS_queue_item_len); //quenue for GPS

if( GPS_queue == NULL ) {

console("ERROR QUEUE NOT CREATED, not enough memory\r\n");

}

Čakalna lista torej lahko shrani 10 struktur, vsaka struktura vsebuje kazalec na pridobljene GPS podatke ter količino podatkov

struct buffer_t{

uint8_t * p_data;

uint32_t length;

};

Posredovanje kazalca na podatke je sicer bolj komplicirano, kot če bi se prejeti podatki preprosto kopirali v čakalno listo, saj je potrebno zagotoviti, da opravilo, ki bere čakalno listo sprosti rezervirani pomnilnik po tem, ko podatke prebere. Je pa prav zaradi tega lahko čakalna lista veliko manjša.

Ko opravilo čaka na nov element v čakalni listi, lahko za določen čas operacijski sistem to opravilo ustavi in ga zopet zažene takoj, ko se pojavi nov element v čakalni listi, če se takrat ne izvaja opravilo z višjo prioriteto. Maksimalen čas, za katerega želimo, da se opravilo ustavi, nastavimo ob klicu funkcije xQueueReceive.

Ta čas se po navadi nastavi na nekaj sekund, saj mora opravilo periodično resetirati watchdog števec, zato se ne sme predolgo čakati na element v listi.

V poglavju Opravilo »gps_task« je predstavljena tudi uporaba te čakalne liste za komunikacijo med UART prekinitvijo in gps opravilom.

Program je razdeljen v 11 opravil, ki so opisani v naslednjih podpoglavjih.

3.2 Opravilo commands_task

Program ima trenutno 44 možnih ukazov, ukazi se lahko preprosto dodajajo s klicem funkcije FreeRTOS_CLIRegisterCommand, funkciji pa je potrebno kot parameter podati strukturo CLI_Command_Definition_t, ki vsebuje ime ukaza, opis ukaza (ta se uporabniku prikaže ob klicu ukaza »help«), funkcijo, ki jo bo operacijski sistem poklical ob prejetem ukazu, in pa pričakovano število parametrov ukaza (za ukaze, kjer je možno različno število parametrov, se uporabi -1).

Kot primer je predstavljen ukaz »readpin« , ki prebere stanje željenega GPIO pina. Spodnja koda prikazuje registracijo novega ukaza.

static const CLI_Command_Definition_t xread_pin =

(18)

18 Error! Use the Home tab to apply Naslov 1 to the text that you want to appear here.

{

"readpin", /* The command string to type. */

"\rreadpin:\r\nreads pin that is in parameter\r\n", prvread_pin, /* The function to run. */

1 /* one parameter is expected. */

};

FreeRTOS_CLIRegisterCommand( &xread_pin );

Po prejemu ukaza se pokliče funkcija »prvread_pin« , v parametru uporabnik zapiše kateri pin želi prebrati, to informacijo v programu ugotovimo s funkcijo FreeRTOS_CLIGetParameter, v spremenljivko pin_string se prepiše vrednost parametra v tekstovni obliki, številčno vrednost parametra nato dobimo s funkcijo atoi(), ki pretvori tekst v spremenljivko tipa »int«, nato preberemo vrednost pina s funkcijo nrf_gpio_pin_read(pin) , vrednost shranimo v spremenljivko pin_state, nato sestavimo odgovor na ukaz, ki ga shranimo v medpomnilnik pcWriteBuffer. To storimo s funkcijo sprintf().

static BaseType_t prvread_pin( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )

{

BaseType_t pin_len = 0;

char* pin_string;

pin_string = (char*)FreeRTOS_CLIGetParameter( pcCommandString, 1, &pin_len );

int pin = atoi(pin_string);

int pin_state = nrf_gpio_pin_read(pin);

snprintf(pcWriteBuffer, xWriteBufferLen, "PIN %d VALUE: %d

\n",pin, pin_state);

return pdFALSE;

}

3.3 Opravilo BLE_task

BLE opravilo preko preko čakalne liste »BLE_queue« pridobi zahteve za klic funkcij povezanih z BLE periferijo. Tega dela programa ne bom podrobno razlagal, saj je to opravilo delo sodelavca v podjetju.

(19)

Error! Use the Home tab to apply Naslov 2 to the text that you want to appear here. 19

3.4 Opravilo modem_task

Opravilo »modem_task« je zadolženo za komunikacijo z modemom. Opravilo pridobi potrebne podatke s pomočjo čakalne liste »modem_queue«, struktura v čakalni listi je sestavljena iz tipa podatka, kazalca na podatek in pa dolžino podatka.

V primeru, ko je tip podatka »GSM_TXRECORD« to pomeni, da je potrebno podatke posredovati modemu, v nasprotnem primeru pa gre za podatke, ki so bili prejeti preko UART komunikacije (glej poglavje UART komunikacija z modemom).

Ko je tip podatka »GSM_TXRECORD«, to pomeni, da je na naslovu, kamor kaže kazalec, struktura za pošiljanje. Ta struktura vsebuje sporočilo, ki ga je potrebno prenesti modemu, dolžino sporočila, pričakovan odgovor, čas čakanja na odgovor in pa informacija, če je potrebno shraniti celoten odgovor modema. Pošiljanje se izvede s klicem funkcije send_modem_command(), ki pošlje podatke na modem s pomočjo funkcije nrf_libuarte_async_tx(). Za večjo zanesljivost se v primeru neuspešnega pošiljanja podatki pošljejo ponovno, med ponovnimi poizkusi pa je 1 sekundo zakasnitve.

Spodnja koda prikazuje proces pridobitve sporočila preko čakalne liste in pošiljanje sporočila modemu.

if (xQueueReceive(getmodem_queue(), &(modem_message), 1000) ==

pdPASS) //blocks for 1s if queue is empty {

if(modem_message.data_type == GSM_TXRECORD) {

GSM_TxRecordType* p_toGSMTX = (GSM_TxRecordType*)modem_message.p_data;

qird_command = 0;

ret_code_t mdm_ret_val = NRF_SUCCESS; //try sending 3 times if sending fails

int8_t retrys = 3;

while(retrys) {

if(send_modem_command(p_toGSMTX->txText, p_toGSMTX-

>txLength) == NRF_SUCCESS) {

break;

} else {

vTaskDelay(1000);

retrys--;

} }

Ko se podatki pošljejo na modem, se v primeru, da je bil podan čas čakanja na odgovor, nastavi časovnik. To se stori s klicema funkcij

(20)

20 Error! Use the Home tab to apply Naslov 1 to the text that you want to appear here.

xTimerChangePeriod(modem_command_timer_h, čas ), kjer se nastavi željen čas časovnika in pa funkcijo xTimerStart(modem_command_timer_h, 0) ki časovnik zažene.

V času trajanja štetja časovnika se preverja ali je modem že poslal pričakovan odgovor. Ko UART periferija pridobi podatke, jih preko čakalne liste posreduje opravilu »modem_task«, ta potem shranjuje te podatke v medpomnilnik in preverja če je že prišel pričakovan odgovor. Pričakovani odgovor je v veliki večini primerov

»OK\r\n« (na primer modemu se pošlje neka zahteva in če je ta zahteva uspešno opravljena, odgovori z OK). Odgovor se preverja s funkcijo strncmp(param1, param2, param3), kot prvi parameter funkcije se poda pričakovan odgovor, kot drugi parameter pa najnovejša vrstica, ki jo je poslal modem, kot tretji parameter pa dolžino, ki se primerja, to je kar dolžina pričakovanega odgovora.

V primeru, da je modem poslal pričakovan odgovor, se pokliče funkcija command_subscribers_callback, ki sporoči klicatelju, da je dobil pričakovan odgovor in sprosti ves spomin, ki je bil v tem procesu rezerviran.

Če pričakovanega odgovora ni (na primer, ko se nastavi določen parameter na modemu in se pričakuje »OK\r\n«, vendar zahteve modem ni uspel izvesti, zato odgovori z »ERROR«) potem se klic funkcije command_subscribers_callback ne izvede, se pa ob poteku časovnika pokliče funkcija modem_command_timeout_handler, ki sporoči klicatelju, da modem ni poslal pričakovanega odgovora; ob tem pa sprosti tudi ves pomnilnik, ki je bil v tem procesu rezerviran.

3.5 Opravilo gps_task

Opravilo »gps_task« je namenjeno pridobivanju in procesiranju podatkov iz GPS modula. Tu je v času razvijanja prišlo do kar nekaj sprememb. Najprej smo implementirali branje podatkov preko I2C povezave, vendar se je pozneje pojavila potreba po UART komunikaciji (saj morebitni novi GPS modul ne podpira I2C komunikacije), zato se ta način ne uporablja več. Poleg tega pa se še ne ve, ali se bo uporabljal modem z vgrajenim GPS modulom (v tem primeru so UART linije povezane na pomožni UART na modemu debug UART) ali pa se bo uporabljal samostojni GPS modul (v tem primeru so seveda UART linije povezane na njegove UART pine). Da bi bilo z vsem tem povzročeno čim manj zmede, je programska oprema napisana tako, da deluje tako z GPS modulom vgrajenim v modem, kot s samostojnim GPS modulom.

(21)

Error! Use the Home tab to apply Naslov 2 to the text that you want to appear here. 21

To smo naredili tako, da smo na začetku izvajanja programa nastavili UART periferijo na hitrost prenosa 9600, saj je samostojni GPS modul nastavljen na delovanje s to hitrostjo prenosa. Modul bi moral, ne glede na to ali ima podatke o poziciji ali ne, vsako sekundo pošiljati podatke. Zato v primeru, da podatkov ni, pomeni, da naprava nima priključenega samostojnega GPS modula. Zato se prestavi hitrost prenosa iz 9600bps na 115200bps, saj s to hitrostjo oddaja podatke vgrajeni GPS v modemu in pa modemu se pošlje zahteva za vklop GPS modula. V primeru, da tudi pri tej hitrosti prenosa ni podatkov, se izklopi napajanje za GPS periferijo in se ga po 1 sekundi vklopi nazaj in poizkusi ponovno.

Torej, ne glede na vir GPS podatkov , podatki vedno pridejo na procesor preko UART periferije. Ko prispejo novi podatki, se zgodi prekinitev. V prekinitvi se kazalec na prispele podatke in pa dolžina podatkov shranijo v čakalno listo »GPS_queue«, v čakalno listo se prenesejo s klicem funkcije xQueueSendToBackFromISR, kar je prikazano spodaj.

void uart_event_handler_gps(void * context, nrf_libuarte_async_evt_t * p_evt)

{

ret_code_t ret;

switch (p_evt->type) {

case NRF_LIBUARTE_ASYNC_EVT_RX_DATA:

{

//GPS data

uint32_t rx_amount = p_evt->data.rxtx.length;

struct buffer_t data_out;

data_out.p_data = p_evt->data.rxtx.p_data;

data_out.length = rx_amount;

if(xQueueSendToBackFromISR(getGPS_queue(),

&data_out, NULL) != pdTRUE ) {

console("ERROR sending data to GPS queue");

}

Čakalna lista se nato prebere v gps opravilu s klicem funkcije xQueueReceive().

struct buffer_t GPS_data;

if(xQueueReceive(GPS_queue, &(GPS_data), 1000) == pdPASS) //blocks for 1s if queue is empty

{

V strukturi GPS_data je zdaj kazalec na GPS podatke in dolžina teh podatkov.

Nato naprava začne s procesiranjem dobljenih podatkov. Podatki so v obliki

(22)

22 Error! Use the Home tab to apply Naslov 1 to the text that you want to appear here.

NMEA0183 stavkov, ki so v napravi lahko naslednjih tipov (seveda je vseh tipov NMEA0183 stavkov še več):

• RMC stavek nosi informacijo o trenutnem času (leto, dan, ure, minute, sekunde). Ta informacija se uporablja tudi za nastavitev časa na napravi.

• GGA stavek nosi informacijo o poziciji (torej o zemljepisni dolžini in zemljepisni širini v stopinjah), številu satelitov, iz katerih je bila pozicija določena in pa stopnjo kvalitete določene pozicije (če je na primer satelitov malo, je stopnja kvalitete majhna, saj pozicija ni tako natančna).

• GSV stavek nosi več podatkov o satelitih, pove tudi nadmorsko višino.

• VTG stavek nosi podatke o trenutni hitrosti in o kotu gibanja.

Vsak NMEA0183 stavek se začne z znakom '$' in konča z znakom '\n'. Najprej si program rezervira 80 bajtov velik medpomnilnik za hranjenje posameznega NMEA0183 stavka z imenom nmea_message (velikost 80 bajtov je zato, ker je to največja možna dolžina NMEA0183 stavka), nato pa se vsak bajt podatkov eden za drugim prepiše v medpomnilnik nmea_message. Začne se z znakom '$' in ko se pojavi znak '\n', to pomeni konec stavka. Nato se pokliče funkcija GPS_NMEAparse(&nmea_message, &data_GPS), ki kot parameter sprejme pravkar prebran NMEA0183 stavek, drugi parameter pa je struktura data_GPS, ki hrani vse podatke o zadnji GPS poziciji. Funkcija GPS_NMEAparse nato zamenja stare podatke v strukturi s pravkar pridobljenimi. To stori s pomočjo funkcij iz knjižnice minmea.

Kot primer NMEA0183 stavka je spodaj predstavljen primer stavka GGA.

$GPGGA,125017.00,4602.673,N,01429.362,E,1,07,0.9,2864.0,M,46.9,M,,,,*47

Izsek stavka pomen

GGA Global Positioning System Fix Data

125017.00 Podatek zajet ob uri 12:50:17 UTC

4602.673,N Latituda (Geografska širina), 46 stopinj 2,673 minute severno od ekvatorja

01429.362,E Longituda (Geografska dolžina), 14

stopinj 29,362 minute vzhodno od začetnega poldnevnika

1 Kvaliteta podatka:

• 0 = napačen

• 1 = veljaven GPS podatek

• 2 = DGPS (diferencialni GPS) podatek

• 3 = PPS podatek

07 Število satelitov

(23)

Error! Use the Home tab to apply Naslov 2 to the text that you want to appear here. 23

0.9 Horizontalna slabitev lokacije

2864.0,M Nadmorska višina v metrih

46.9,M Višina geoida nad elipsoidom WGS84

*47 Kontrola pravilnosti v šestnajstiški obliki

( v tem primeru ni pravilna saj so podatki izmišljeni za potrebe demonstracije)

Tabela 3.1: NMEA0183 stavek GGA

Ko so procesirani vsi NMEA0183 stavki, ki so prišli v določenem paketu, to pomeni, da so podatki v strukturi data_GPS veljavni. Zaradi varčevanja s podatkovnim prometom in energijo se nova pozicija pošilja na strežnik samo, če je nova točka oddaljena od prejšnje za določeno razdaljo ali pa če je naprava spremenila kot gibanja za določeno vrednost. Ti dve vrednosti sta shranjeni v notranjem FLASH pomnilniku naprave in se ob vsakem prižigu naprave naložita v RAM pomnilnik.

Po procesiranju prejetih GPS stavkov je potrebno še sprostiti UART medpomnilnik. To se stori s klicem funkcije nrf_libuarte_async_rx_free, kateri se poda kazalec na začetek dela pomnilnika, ki ga je potrebno sprostiti, ter njegovo velikost.

3.6 Opravilo data_task

Data opravilo je namenjen prejemanju podatkov s strežnika, na primer ukaze (glej poglavje commands_task).

Ko strežnik želi poslati podatke na modem, modem opozori na čakajoče podatke z »+QIURC«, ki ga preko UART komunikacije in čakalne liste prejme že prej omenjeni modem task. Ta potem pokliče funkcijo URC_callback_func(), kjer se s klicem funkcije xEventGroupSetBitsFromISR( URC_event_group, INCOMING_DATA_BIT, NULL) postavi zastavica INCOMING_DATA_BIT.

Opravilo »data task« pa ob postavitvi te zastavice začne z branjem in procesiranjem prejetih podatkov. Za potrebe branja se najprej s funkcijo BM_malloc(READ_BUF_SIZE) rezervira medpomnilnik velikosti 1kB. Funkcija BM_malloc pokliče fukcijo operacijskega sistema za rezervacijo medpomnilnika pvPortMalloc(malloc_size), ob tem pa še javi napako, če medpomnilnika ni bilo možno rezervirati. Ob uspešni rezervaciji medpomnilnika se pokliče funkcija GPRS_receive, ki modemu pošlje zahtevo za branje prejetih podatkov. Po branju

(24)

24 Error! Use the Home tab to apply Naslov 1 to the text that you want to appear here.

funkcija GPRS_parseServerData še procesira prejete podatke (ta funkcija zaradi poslovnih skrivnosti ni podrobneje opisana).

3.7 Opravilo can_task

Opravilo can_task je namenjeno komunikaciji s CAN integriranim vezjem. CAN (ang. Controller Area Network) je digitalni sistem, ki se uporablja v plovilih za komunikacijo med posameznimi elektronskimi sistemi. CAN komunikacijo je navtična industrija povzela po avtomobilski, ki tako vrsto komunikacije uporablja že zelo dolgo (že od leta 1987), v navtiki pa je CAN komunikacija še vedno relativno nova. Za pošiljanje in sprejem CAN sporočil je uporabljen IC MCP2515, s katerim procesor komunicira preko SPI povezave, ki je opisana v poglavju SPI komunikacija s CAN integriranim vezjem.

Najprej je potrebno zagotoviti, da je CAN IC nastavljen na pravilne nastavitve, da bo lahko sprejemal sporočila po CAN liniji. To nastavimo s funkcijo mcp_can_begin(CAN_250KbPS), 250 KbPS je hitrost CAN komunikacije na plovilu.

CAN IC je nastavljen tako, da ob prejetem CAN sporočilu nastavi prekinitveno linijo na nizko stanje (proces konfiguracije je opisan spodaj). Zato je potrebno nastaviti prekinitev na procesorju, da se lahko takoj po prejetem sporočilu le-tega tudi prebere.

Prekinitev se nastavi na enak način, kot je predstavljeno v poglavju I2C komunikacija z razširjevalcem GPIO pinov.

V funkciji mcp_can_begin se nastavijo še ostali parametri, pomembni za delovanje.

Najprej je potrebno CAN IC prestaviti v način konfiguracije, kar storimo s klicem funkcije mcp2515_setCANCTRL_Mode(MODE_CONFIG)

uint8_t mcp2515_setCANCTRL_Mode(const uint8_t newmode) {

uint8_t i;

mcp2515_modifyRegister(MCP_CANCTRL, MODE_MASK, newmode);

nrf_delay_ms(5);

i = mcp2515_readRegister(MCP_CANCTRL);

i &= MODE_MASK;

if ( i == newmode ) {

return MCP2515_OK;

}

return MCP2515_FAIL;

(25)

Error! Use the Home tab to apply Naslov 2 to the text that you want to appear here. 25

}

Funkcija mcp2515_modifyRegister(MCP_CANCTRL, MODE_MASK, newmode) spremeni stanje registra MCP_CANCTRL.

različni načini delovanja CAN IC vir[8]

Vrednosti bitov REQOP[2:0] v registru CANCTRL

Način delovanja čipa

000 Normalni način

001 Način spanja

010 Način povratne zanke

011 Način poslušanja

100 Konfiguracijski način

Za nastavitev konfiguracijskega načina je potrebno na bite 7, 6 in 5 v registru CANCTRL napisati vrednosti 1, 0 in 0. CAN IC podpira poleg pisanja vrednosti registra tudi spreminjanje samo določenih bitov. To je uporabno, ker je potrebno spreminjati vrednost samo treh bitov (druga možnost bi bila branje registra, sprememba samo določenih bitov in pisanje celotnega registra nazaj).

Funkcija mcp2515_modifyRegister najprej naslovi CAN IC, kar stori s klicem funkcije mcp_select(), ki postavi linijo CS na nizko stanje. Nato pošlje zahtevo za spremembo bitov. Za tem pošlje naslov registra, ki ga je potrebno spremeniti, nato pošlje masko, ki pove, kateri biti v registru se bodo spreminjali, nazadnje pa še novo vrednost. Na koncu je potrebno še zaključiti komunikacijo, kar se naredi s postavitvijo CS linije na visok nivo s pomočjo funkcije mcp_unselect.

Prikaz procesa spreminjanja bitov na konkretnem primeru (nastavitev konfiguracijskega načina):

Začetna vrednost registra CANCTRL(neznana) 𝑥𝑥𝑥𝑥 𝑥𝑥𝑥𝑥

Maska za spreminjanje bitov 1110 0000

Nastavitvena vrednost 1000 0000

(26)

26 Error! Use the Home tab to apply Naslov 1 to the text that you want to appear here.

Nova vrednost registra po nastavitvi 100𝑥 𝑥𝑥𝑥𝑥

(kjer x pomeni, da register ohrani vrednost, ki jo je imel pred spominjanjem) Ko je CAN IC v konfiguracijskem načinu, se lahko nadaljuje z nastavljanjem hitrosti CAN povezave, ki je podana ob klicu funkcije mcp_can_begin in je v mojem primeru 250KbPS. Nato se s klicem funkcije mcp2515_initCANBuffers nastavijo vhodni medpomnilniki. Nato se nastavi, da bo CAN IC sprožil prekinitev v primeru, da je katerikoli od vhodnih medpomnilnikov napolnjen, to stori s klicem

𝑚𝑐𝑝2515_𝑠𝑒𝑡𝑅𝑒𝑔𝑖𝑠𝑡𝑒𝑟(𝑀𝐶𝑃_𝐶𝐴𝑁𝐼𝑁𝑇𝐸, 𝑀𝐶𝑃_𝑅𝑋0𝐼𝐹 | 𝑀𝐶𝑃_𝑅𝑋1𝐼𝐹);

Kjer je MCP_RX0IF = 0000 0001 in MCP_RX1IF = 0000 0010 (seveda v dvojiškem številčnem sistemu)

Torej je nova vrednost registra:

0000 0001 | 0000 0010 = 0000 0011

Iz stanja CANINTF registra pridobimo razlog, zaradi katerega se je zgodila prekinitev. CAN IC MCP2515 ima namreč 2 medpomnilnika za hranjenje CAN sporočil (zato da lahko, medtem ko se bere prvo spočilo, že sprejema naslednjega).

Nato sledi branje ustreznega medpomnilnika, prebrano CAN sporočilo se nato shrani v strukturo CAN_data in s pomočjo funkcije xQueueSendToBackFromISR pošlje v čakalno listo, ki se bere v opravilu CAN. Branje se nadaljuje v while zanki, dokler niso prebrani vsi medpomnilniki.

static void CAN_event_handler() {

uint8_t stat;

uint8_t ret = 0;

stat = mcp2515_readStatus();

CanRxMsg CAN_data = {0};

CanRxMsg * p_CAN_data = &CAN_data;

while( stat & MCP_STAT_RX0IF || stat & MCP_STAT_RX1IF ) {

if(stat & MCP_STAT_RX0IF) {

ret = readmcp2515_buf(MCP_RXB0SIDH, p_CAN_data);

}

else if(stat & MCP_STAT_RX1IF) {

ret = readmcp2515_buf(MCP_RXB1SIDH, p_CAN_data);

}

if(ret == CAN_OK)

(27)

Error! Use the Home tab to apply Naslov 2 to the text that you want to appear here. 27

{

if(xQueueSendToBackFromISR(getCAN_queue(),

&CAN_data, NULL) != pdPASS ) {

console("sending CAN message to queue failed");

} }

stat = mcp2515_readStatus();

} }

» can_task« nato bere CAN sporočila iz čakalne liste in se na njih ustrezno odzove. Tega dela ne bom predstavljal, saj je delo sodelavca v podjetju.

3.8 Opravilo meas_task

Opravilo »meas_task« skrbi za procesiranje meritev, ki jih naprava zajema.

Naprava ima 22 senzorjev, katerih vrednosti se ob vsakem javljanju lokacije na strežnik pošiljajo skupaj z lokacijo (z namenom da se potem lahko uporabniku prikazujejo na mobilni aplikaciji). Vrednosti se pošiljajo tudi v primeru, ko se neka vrednost drastično spremeni (na primer močno pade napetost na bateriji).

Vrednosti senzorjev se preko čakalne liste pošiljajo v meas_task. Vsak senzor ima določen identifikator, ki ga pošlje ob vrednosti. Opravilo nato ob prejemu novih meritev kliče funkcijo sensor_processing(), ki nove vrednosti primerja s starimi in ustrezno ukrepa (v RAM pomnilniku se seveda hranijo vse dosedanje vrednosti senzorjev). V čakalno listo se vrstijo meritve iz različnih virov, na primer:

• Vrednosti iz petih ADC pretvornikov, ki se uporabljajo za merjenje napetosti na notranji bateriji in na štirih zunanjih virih (po navadi so to akumulatorji na plovilu).

• Vrednosti iz štirih digitalnih vhodov (te se pridobivajo z branjem razširjevalca GPIO pinov), digitalni vhodi se v praksi uporabljajo za priklop zunanjih senzorjev, ki nam na primer povejo ali na plovilu trenutno deluje drenažna črpalka, ali so odprta vrata in ali je plovilo priključeno na električno omrežje v marini.

• Vrednosti, ki jih pošilja modem, na primer jakost signala, mobilni operater, na katerega je naprava povezana, in pa poraba mobilnih podatkov.

• Vrednosti, ki jih pošilja GPS, na primer število satelitov, iz katerih je pridobljena trenutna lokacija.

(28)

28 Error! Use the Home tab to apply Naslov 1 to the text that you want to appear here.

• Vrednosti, ki jih pošilja pospeškometer, na primer najvišji pospešek v zadnji sekundi, temperatura, itd.

3.9 Opravilo accel_task

Opravilo »accel_task« je namenjeno branju in obdelavi podatkov iz pospeškometra. Na napravi uporabljamo pospeškometer LSM6DSM, možna pa je tudi uporaba LSM6DS3. Pospeškometra imata kompatibilni podnožji in večina registrov je enakih, programska oprema je napisana tako, da sama zazna, kateri pospeškometer je prisoten na vezju in ustrezno nastavi tiste registre, ki se razlikujejo.

Ob zagonu naprave opravilo najprej nastavi pospeškometer. To dosežemo z nastavljanjem CTRL registrov. Pred nastavljanjem najprej preberemo register WHO_AM_I (0Fh), ki pove, kateri pospeškometer je položen na napravo. Če je vrednost registra 0x6A pomeni, da je to LSM6DSM; če pa je 0x69, pa LSM6DS3.

Podroben proces branja in pisanja registrov je podrobneje opisan v poglavju "I2C komunikacija z razširjevalcem GPIO pinov", saj pospeškometer za komunikacijo uporablja I2C; opisal bom samo registre, ki so potrebni za nastavitev in pa njihovo funkcijo.

Ime registra in njegov naslov funkcija

CTRL3 (12h) Nastavitev prekinitvene linije – nizko stanje linije pomeni aktivno prekinitev, avtomatsko povečevanje naslova registra pri zaporednem branju, nastavitev LSB najprej (torej najmanj pomemben bit je prenesen najprej)

CTRL1_XL (10h) Nastavitev pasovne širine (200Hz),

nastavitev območja delovanja(2g), nastavitev frekvence vzorčenja(208Hz) FIFO_CTRL3 (08h) Vklop FIFO registra in nastavljanje

deljenja vrednosti pospeška v FIFO registru (brez deljenja)

(29)

Error! Use the Home tab to apply Naslov 2 to the text that you want to appear here. 29

FIFO_CTRL5 (0Ah) Nastavitev tipa FIFO registra

(neprekinjeno delovanje) in nastavitev vzorčne frekvence FIFO registra (104Hz) TAP_CFG (58h) Vklop prekinitev in nastavitev detekcije

za trk v x, y in z smeri

TAP_THS_6D (59h) Nastavitev pragu za detekcijo trka: izbrali smo vrednost 375mg, saj nam ta vrednost omogoča dobro detekcijo trka brez bojazni, da bi trk zaznali tudi ob manjših premikih. Potrebna vrednost registra se izračuna po spodnji enačbi:

𝑥 ∗𝑟𝑎𝑛𝑔𝑒

25 = 375𝑚𝑔 𝑥 =25∗ 375𝑚𝑔

2 𝑥 = 6

INT_DUR2 (5Ah) V registru INT_DUR2 se nastavijo 3 časovne vrednosti. S prvimi štirimi biti (biti 7 do 4) se nastavi maksimalen čas med dvema trkoma ki jih pospeškometer zazna kot 1 dvojni trk. Nastavi se vrednost 2, kar pomeni čas 300ms.

Naslednja dva bita (bita 3 in 2) nastavita minimalni čas med dvema trkoma, da naprava to zazna kot dvojni trk. Nastavi se vrednost 2 kar pomeni 40ms.

Zadnja dva bita (bita 1 in 0) nastavita še največji čas trka, ki ga naprava še zazna kot trk in ne konstantni pospešek, nastavi se vrednost 1 kar pomeni 40ms. Izračuni ter podrobnejša razlaga teh vrednosti so predstavljeni pod tabelo.

Končna vrednost registra INT_DUR2 je tako 0x29.

(30)

30 Error! Use the Home tab to apply Naslov 1 to the text that you want to appear here.

WAKE_UP_THRS (5Bh) Vključitev detekcije enojnega in dvojnega trka

MD2_CFG (5Fh) Vključitev proženja prekinitve na pin INT2 ob zaznanju dvojnega trka (pin INT2 je povezan z našim procesorjem)

Tabela 3.2: Nastavitev registrov pospeškometra

Za maksimalen čas med dvema trkoma ki jih pospeškometer zazna kot 1 dvojni trk je najbolj primeren čas okoli 300ms, vrednost tega dela registra se izračuna po spodnji enačbi

300𝑚𝑠 = 𝑥 ∗ 32 ∗ 1 𝑓𝑣𝑧𝑜𝑟𝑐𝑒𝑛𝑗𝑎 𝑥 =300𝑚𝑠 ∗ 208𝐻𝑧

32 𝑥 = 1,95

Ker pa mora seveda x biti celo število se vrednost zaokroži na 2.

Nato smo nastavili minimalni čas med dvema trkoma, da naprava to zazna kot dvojni trk. Ta čas mora biti čim krajši vendar pa ne sme biti prekratek, saj bi lahko v tem primeru naprava že šum v prvem trku zaznala kot dvojni trk. Izbrali smo čas 40ms, vrednost registra se izračuna po spodnji enačbi.

40𝑚𝑠 = 𝑥 ∗ 4 ∗ 1 𝑓𝑣𝑧𝑜𝑟𝑐𝑒𝑛𝑗𝑎 𝑥 =40𝑚𝑠 ∗ 208𝐻𝑧

4 𝑥 = 2,08 Kar se zaokroži na 2.

Nato se nastavi še največji čas trka, ki ga naprava še zazna kot trk in ne konstantni pospešek, to vrednost smo tudi nastavili na 40ms, vrednost registra se izračuna po spodnji enačbi.

40𝑚𝑠 = 𝑥 ∗ 8 ∗ 1 𝑓𝑣𝑧𝑜𝑟𝑐𝑒𝑛𝑗𝑎 𝑥 =40𝑚𝑠 ∗ 208𝐻𝑧

8 𝑥 = 1,04 Kar se zaokroži na 1.

Kot je razvidno iz nastavitve registrov, se pospeškometer uporablja za merjenje pospeška v x, y in z smeri s frekvenco 104 Hz in za detekcijo dvojnega trka. Meritve pospeška se shranjujejo v FIFO register, ki se periodično prebira v opravilu. Ob

(31)

Error! Use the Home tab to apply Naslov 2 to the text that you want to appear here. 31

zaznanju dvojnega trka se sproži prekinitev, ki je nastavljena podobno kot v poglavju I2C komunikacija z razširjevalcem GPIO pinov. Ob prekinitvi se pokliče funkcija double_tap_event_handler, ta ob klicu posreduje informacijo o trku opravilu meas_task preko čakalne liste.

Pred branjem vzorcev v FIFO registru se najprej izvede branje statusnih registrov 1 in 2, vrednost se shrani v spremenljivko status_reg. Če število vzorcev ni deljivo s 3, se zmanjšuje toliko časa, dokler to ne postane. S tem je zagotovljeno da se vedno preberejo vse 3 koordinate pospeška naenkrat.

uint16_t status_reg = LSM6DS3_read_FIFO_status();

status_reg = status_reg & 0x07FF;

while((status_reg%3) != 0) // to read all x,y and z on the same time

{

status_reg--;

}

uint16_t n_of_vectors = status_reg/3;

Nato se rezervira medpomnilnik za hranjenje podatkov, velikost medpomnilnika pa je status_reg * 2, ker je vsak vzorec velik 2 bajta. Nato se v zanki izvaja branje FIFO registra, kot prikazuje spodnja koda.

AccVector * vector;

if(status_reg != 0) {

vector = BM_malloc(status_reg*2);

if(vector != NULL) {

for(int i =0; i<(n_of_vectors); i++) {

vector[i].x = LSM6DS3_read_FIFO_buffer();

vector[i].y = LSM6DS3_read_FIFO_buffer();

vector[i].z = LSM6DS3_read_FIFO_buffer();

}

Iz pridobljenih podatkov funkcija IMU_vectorPeakIntegral izračuna najvišjo amplitudo pospeška, poišče vektor z najvišjim pospeškom in izračuna integral amplitud vektorjev. Te vrednosti se potem kot vrednosti senzorjev pošiljajo v meas_task preko čakalne liste.

(32)

32 Error! Use the Home tab to apply Naslov 1 to the text that you want to appear here.

3.10 Opravilo usbd_task

To opravilo je zadolženo za vzpostavitev in ohranjanje USB povezave z računalnikom. Povezava se uporablja za izpisovanje napak in informacij o delovanju naprave in tudi za upravljanje naprave s pošiljanjem ukazov.

3.11 Opravilo logger_task

Opravilo logger_task ima izmed vseh opravil najnižjo prioriteto. Procesorski čas dobi samo v primeru, ko so vsa ostala opravila v stanju pripravljenosti. V opravilu logger_task se izvaja izpis na USB konzolo (če je le-ta priključena).

3.12 Varnostni časovnik

Varnostni časovnik (angl. Watchdog), ki ga včasih imenujemo samo časovnik ali čuvaj, je elektronski ali programski časovnik, ki se uporablja za vzpostavitev normalnega delovanja po pojavu kritične napake. Med normalnim delovanjem programa procesor redno ponastavlja časovnik, da prepreči iztek le-tega. Če procesor ne resetira časovnika, se števec izteče in ustvari timeout signal. Timeout signal se uporablja za sprožitev popravnih ukrepov, v našem primeru to pomeni vnovičen zagon naprave.

Ker je v našem sistemu večje število opravil, obstaja nevarnost, da se proces

»zacikla« v kateremkoli od teh opravil, zato je potrebno poskrbeti, da časovnik v določenem časovnem obdobju resetira vsa opravila. Za to smo ustvarili funkcijo wd_update, ki jo morajo v roku 20 sekund poklicati vsa opravila. Če se to ne zgodi, pomeni, da se je program ustavil v enem izmed opravil, zato pride do ponastavitve naprave.

//check if each task set a flag to reset watchdog timer void wd_update(TaskHandle_t current_task)

{

int j=0, i=0, m=0;

for(i=0; i<WD_TASKS; i++) {

if(WD_RESET[i] == current_task)//if task handle is already in WD_RESET array do nothing

(33)

Error! Use the Home tab to apply Naslov 2 to the text that you want to appear here. 33

{

break;

}

if(i ==(WD_TASKS -1))//task handle does not exist in WD_RESET array

{

for(j=0; j<WD_TASKS; j++) {

if(j == WD_TASKS - 1) //that means all tasks called wd_update function -> reset WDT timer

{

nrf_drv_wdt_channel_feed(m_channel_id);

for(m=0; m < (WD_TASKS); m++) {

WD_RESET[m] = 0;

} break;

}

if(WD_RESET[j] == 0) //save task handle in WD_RESET array

{

WD_RESET[j] = current_task;

break;

} } } } }

(34)
(35)

35

4 Komunikacija s periferijo

Za zajem potrebnih podatkov ter komunikacijo je potrebna povezava z različnimi perifernimi napravami. Različne komunikacije so predstavljene v naslednjih poglavjih.

4.1 I2C komunikacija z razširjevalcem GPIO pinov

I2C vodilo je serijsko vodilo, ki za komunikacijo uporablja 2 liniji:

• SDA linija. Po njej se prenašajo podatki iz gospodarja k sužnju ali obratno;

• SCL linija. Linija po kateri se prenašajo urini impulzi za sinhronizacijo komunikacije. Urine impulze generira gospodar.

Potek I2C komunikacije:

1. Gospodar pošlje začetni bit (SCL linija je na visokem stanju, SDA linija pa se spremeni iz visokega na nizko stanje).

2. Gospodar pošlje 7 bitni naslov sužnja.

3. Gospodar z naslednjim bitom pove ali želi pošiljati podatke sužnju (nizko stanje) ali pa jih brati iz njega (visoko stanje).

4. Suženj pošlje »ack« bit, s katerim pove, da je razumel poslano.

5. Začne se prenos podatkov po 8 bitov naenkrat; po vsakih osmih bitih se pošlje »ack« bit.

6. Prenos se konča s stop bitom (SCL linija je na visokem stanju SDA linija pa se spremeni iz nizkega na visoko stanje).

(36)

36 Error! Use the Home tab to apply Naslov 1 to the text that you want to appear here.

Slika 4.1: I2C povezava med gospodarjem in sužnjem [1]

Ker ima mikrokrmilnik, ki ga uporabljamo za našo aplikacijo, premalo GPIO pinov, je bilo potrebno uporabiti integrirano vezje, ki ima dodatnih 16 pinov, katerih vrednosti se lahko berejo in pišejo preko I2C povezave.

Razširjevalec GPIO pinov sproži prekinitev, ko se spremeni stanje na kateremkoli GPIO pinu. V prekinitvi se nato izvede branje vrednosti. Ker se med izvajanjem programa hranijo prejšnje vrednosti GPIO pinov, je možno določiti, kje je prišlo do spremembe. Če se na primer spremeni vrednost na senzorju »vrata« pomeni, da so se na plovilu odprla ali zaprla glavna vrata, spremembo se nato takoj preko modema pošlje na strežnik, ki ustrezno ukrepa (obvesti končnega uporabnika o dogodku).

Spodnja slika prikazuje funkcijo za inicializacijo i2c komunikacije. Najprej je potrebno določiti GPIO pina na procesorju, kjer bo potekala i2c komunikacija; pina je potrebno nastaviti kot vhoda z vključenim pull-up vporom.

Potem sledi funkcija nrf_twi_init(), vhodni podatki funkcije so instanca, katero želimo, da procesor uporablja za komunikacijo in pa konfiguracijska struktura, kjer se vnese uporabljene GPIO pine, želeno hitrost prenosa podatkov ter prioriteto.

Sledi še konfiguracija prekinitve, kar se stori s funkcijo nrf_drv_gpiote_in_init().

Funkciji je treba podati, na kateri GPIO pin želimo nastaviti prekinitev (predhodno je potrebno ta pin nastaviti kot vhodni pin brez vključenega pull-up vpora). Nastavimo tudi tip prekinitve (razširjevalec GPIO pinov spremeni stanje prekinitvene linije iz visokega na nizko) in pa funkcijo, ki se bo poklicala, ko se bo zgodila prekinitev.

(37)

Error! Use the Home tab to apply Naslov 2 to the text that you want to appear here. 37

//i2c init

nrf_gpio_cfg_input(SCL_PIN_1, NRF_GPIO_PIN_PULLUP);

nrf_gpio_cfg_input(SDA_PIN_1, NRF_GPIO_PIN_PULLUP);

const nrf_drv_twi_config_t twi_1_config = { .scl = SCL_PIN_1,

.sda = SDA_PIN_1,

.frequency = NRF_TWI_FREQ_100K, .interrupt_priority = APP_IRQ_PRIORITY_HIGH, .clear_bus_init = false

};

err_code = nrf_drv_twi_init(&m_twi_1, &twi_1_config, NULL, NULL);

APP_ERROR_CHECK(err_code);

nrf_drv_twi_enable(&m_twi_1);

err_code = NRF_SUCCESS;

nrf_gpio_cfg_input(GPI_INTERRUPT_PIN, NRF_GPIO_PIN_NOPULL);

nrf_delay_ms(5);

nrf_drv_gpiote_in_config_t gpi_config =

GPIOTE_CONFIG_IN_SENSE_HITOLO(false); //proženje interupta nastavljeno, ko gre z visokega na nizko stanje

err_code = nrf_drv_gpiote_in_init(GPI_INTERRUPT_PIN, &gpi_config ,GPI_event_handler); //INTERUPT INIT

APP_ERROR_CHECK(err_code);

nrf_drv_gpiote_in_event_enable(GPI_INTERRUPT_PIN, true);

Naslednja slika prikazuje proces branja vrednosti pinov na razširjevalcu. Za hitrejše branje smo napisali funkcijo, ki kot parameter sprejme, katerega izmed dveh registrov želimo prebrati, nato pa vrne vrednost tega registra.

uint8_t read_register(uint8_t reg) {

uint8_t read_result = 0;

nrf_drv_twi_xfer_desc_t data_in;

data_in.type = NRF_DRV_TWI_XFER_TX;

data_in.address = GPIO_EXT_ADDRESS;

data_in.primary_length = 1;

data_in.p_primary_buf = &reg;

ret_code_t err_code = nrf_drv_twi_xfer(&m_twi_1, &data_in, NRF_DRV_TWI_FLAG_NO_XFER_EVT_HANDLER);

nrf_drv_twi_xfer_desc_t data_out;

data_out.type = NRF_DRV_TWI_XFER_RX;

data_out.address = GPIO_EXT_ADDRESS;

(38)

38 Error! Use the Home tab to apply Naslov 1 to the text that you want to appear here.

data_out.primary_length = 1;

data_out.p_primary_buf = &read_result;

err_code = nrf_drv_twi_xfer(&m_twi_1, &data_out, NRF_DRV_TWI_FLAG_NO_XFER_EVT_HANDLER);

return read_result;

}

Pisanje vrednosti izhodov se izvaja tako, da procesor pošlje zahtevo za pisanje, nato pa pošlje željena stanja GPIO pinov. Ker po navadi želimo spreminjati stanje le enega GPIO pina na izhodu, brez da bi spreminjali stanja ostalih pinov, se najprej izvede branje trenutnega stanja, nato z masko spremenimo vrednost le želenega bita in nato se pošljejo nova stanja izhodov nazaj. Lahko pa se seveda spremeni tudi vrednosti vseh pinov naenkrat s funkcijo write_register.

4.2 USB konzola

Predvsem zaradi lažjega razvoja naprave smo implementirali tudi USB povezavo, s katero se lahko preko konzole na osebnem računalniku komunicira z napravo. USB komunikacija se implementira s pomočjo knjižnice usb_cdc_acm.

Pošiljanje izpisov na konzolo se izvede s pomočjo NRF_LOGa, ki med drugim omogoča, da izpisi ne porabijo časa v delu programa, kjer se izpis zgodi, kar je lahko kritično za izvajanje programa (če je na primer USB linija zasedena, mi pa bi želeli do nje dostopati iz prekinitve). Ob klicu funkcije console se izpis samo skopira v medpomnilnik, program pa nato izpise pošilja v ločenem opravilu z najnižjo prioriteto, tako da izpis nima nikakršnega vpliva na izvajanje programa. Vsakemu izpisu se doda tudi čas od začetka izvajanja programa.

4.3 UART komunikacija z modemom

Kratica UART pomeni Universal Asynchronous Receiver/Transmitter. Gre za način serijskega prenosa podatkov v dogovorjeni obliki z dogovorjeno hitrostjo.

(39)

Error! Use the Home tab to apply Naslov 2 to the text that you want to appear here. 39

Boat monitor pošilja vse zajete podatke o plovilu na strežnik, kjer se potem podatki naprej procesirajo in prikazujejo v aplikaciji. Podatki se pošiljajo preko mobilne podatkovne povezave, za kar smo uporabili modem Qeuctel EC21-E. Modem za prenos podatkov uporablja LTE omrežje, predhodnik naprave BM-50 je uporabljal omrežje 3G, vendar ima zaradi prehoda na novejše tehnologije omrežje 3G vedno manjšo pokritost (predvsem v ZDA). Modem ima tudi 60MB flash pomnilnika, ki se uporablja za hranjenje še ne poslanih podatkov (če je plovilo daleč od obale, kjer ni mobilne povezave, se podatki shranjujejo in se nato ponovno pošljejo, ko naprava spet dobi povezavo).

Slika 4.2: modem quectel EC21-E [10]

Po nekaj knjižnicah, ki niso bile primerne za našo uporabo, smo na koncu uporabili knjižnico »libUARTE asynchronous library«; uporabili smo hitrost prenosa 115200 bitov na sekundo.

Ta knjižnica omogoča, da se za sprejem podatkov iz modema lahko določil 3 medpomnilnike, vsak je v našem primeru velik 512 bajtov. Ko se napolni prvi medpomnilnik, se sproži prekinitev, kjer se potem podatki preko čakalne liste pošljejo opravilu, ki jih predela. Med tem časom pa se že polni naslednji medpomnilnik. To pomeni, da ima program dovolj časa za obdelavo podatkov brez možnosti, da bi se ti izgubljali.

(40)

40 Error! Use the Home tab to apply Naslov 1 to the text that you want to appear here.

NRF_LIBUARTE_ASYNC_DEFINE(libuarte2, 0, 1,

NRF_LIBUARTE_PERIPHERAL_NOT_USED, 2, MODEM_QUEUE_LEN, 3);

void init_libuarte_modem(void) {

ret_code_t err_code;

nrf_libuarte_async_config_t nrf_libuarte_async_config2 = { .tx_pin = MODEM_TX_PIN,

.rx_pin = MODEM_RX_PIN,

.baudrate = NRF_UARTE_BAUDRATE_115200, .parity = NRF_UARTE_PARITY_EXCLUDED, .hwfc = NRF_UARTE_HWFC_DISABLED, .timeout_us = 100000,

.int_prio = APP_IRQ_PRIORITY_LOW };

err_code = nrf_libuarte_async_init(&libuarte2,

&nrf_libuarte_async_config2, uart_event_handler_modem, (void

*)&libuarte2);

APP_ERROR_CHECK(err_code);

nrf_libuarte_async_enable(&libuarte2);

}

Z NRF_LIBUARTE_ASYNC_DEFINE se najprej nastavi ime instance, nato številko UART instance, ki jo želimo uporabiti (v našem primeru se uporablja instanco 0 za UART komunikacijo z modemom in 1 za komunikacijo z GPS-jem). Z naslednjim parametrom se pove, katera instanca časovnika bo uporabljena za štetje bajtov; z naslednjima dvema parametroma se nastavi, kako se bo izmeril time out UART komunikacije (libuarte namreč omogoča, da se sproži prekinitev ko je medpomnilnik napolnjen ali pa v primeru, ko določen čas ni novih podatkov). Pri nas je za merjenje time outa izbran časovnik 2 (peti parameter). Če bi želeli time out meriti s pomočjo RTCja, bi bilo potrebno instanco RTCja podati v parameter 4. Naslednje dva parametra pa določata velikost in število medpomnilnikov, ki se bodo ustvarili za potrebe komunikacije. Za komuniciranje z modemom je izbrana hitrost komunikacije 115200 bitov na sekundo, time out pa je nastavljen na 100ms. Nadzora komunikacije s pomočjo strojne opreme se ne uporablja, saj je komunikacija dovolj zanesljiva, hkrati pa na ta način ne uporabimo dveh GPIO pinov.

Komunikacija z modemom poteka preko AT ukazov. Za povezavo z omrežjem je potrebno poslati naslednjo sekvenco ukazov:

(41)

Error! Use the Home tab to apply Naslov 2 to the text that you want to appear here. 41

• Ukaz AT, s tem ukazom preverim ali je modem prižgan. V primeru, da je prižgan modem, vrne AT OK.

• V primeru, da modem ne vrne ničesar, je potrebno modem prižgati. To storimo tako, da postavim POWERKEY pin na modemu na nizko stanje, nato počakamo 1 sekundo in potem nastavimo POWERKEY na visoko stanje. Ko se modem prižge, odgovori s »RDY«.

• Nato z ukazom AT+CPIN? preverimo, če je sim kartica pripravljena na uporabo. To ugotovimo tako, da preverimo, ali je bil odgovor na ukaz

»READY«.

• Nato sledi konfiguracija APN. To storimo z ukazom AT+QICSGP.

• Potem z ukazom AT+COPS=0 prestavimo modem v avtomatsko izbiro operaterja, saj je tako povezava najhitreje vzpostavljena.

• Z ukazom AT+CFUN=1 izberemo polno funkcionalnost omrežja.

• Z ukazom AT+COPS=3,2 nastavimo format odgovora na ukaz AT+COPS?. Ta ukaz format nastavi tako, da razpoložljive operaterje predstavi z numerično kodo.

• Z ukazom AT+CMEE=2 nastavimo, da modem v primeru kakršnekoli napake javi polno sporočilo o napaki in ne samo kodo napake.

• Z ukazom AT+QCFG=\"urc/ri/smsincoming\",\"off\" izklopimo funkcijo zvonjenja, saj naša naprava nima vgrajenega zvočnika.

Modem potrebuje kar nekaj časa, da se poveže na omrežje, zato se po začetni konfiguraciji periodično na nekaj sekund pošilja ukaz AT+CREG?, spodnja slika prikazuje nabor možnih odgovorov na ta ukaz

Slika 4.3: možni odgovori na ukaz AT+CREG? [12]

Ukaz se pošilja, dokler se modem ne poveže na omrežje - to pomeni, da je odgovor na ukaz 1 ali 5.

(42)

42 Error! Use the Home tab to apply Naslov 1 to the text that you want to appear here.

void QUECTELMDM_pwrKeyToggle() {

ext_gpio_write_pin(GSM_POWER, 1); //napajanje izkljuceno vTaskDelay(1000); //vsaj pol s

ext_gpio_write_pin(GSM_POWER, 0); //napajanje vkljuceno }

4.4 Komunikacija z integriranim vezjem za CAN vodilo

Za sprejemanje in oddajanje sporočil po CAN vodilu je uporabljeno integrirano vezje MCP2515, s katerim procesor komunicira preko SPI povezave. SPI je tako kot I2C in UART oblika serijske komunikacije, ki za komunikacijo uporablja 4 linije.

1. MOSI (ang. Master output - slave input) je linija po kateri se prenašajo podatki od naprave, ki je gospodar do naprave, ki je suženj.

2. MISO (ang. Master input – slave output) je linija, kjer podatki tečejo v obratni smeri kot pri MOSI liniji (torej od sužnja proti gospodarju).

3. SCK (ang. Clock) signal ure, potreben, ker je SPI sinhrona oblika komunikacija, kar pomeni, da je čas med posameznimi biti vedno enak, določa pa ga SCK linija z urinimi impulzi.

4. SS/CS (ang. Slave select/chip select) linija za izbor sužnja je pomembna zato, ker je na SPI vodilo lahko priključenih več suženjskih naprav. V tem primeru so le te priključene na iste MOSI, MISO in SCK linije, vsaka naprava pa ima svojo SS linijo, s pomočjo katere lahko gospodarna naprava določa, s katero napravo želi komunicirati.

Spodnja slika prikazuje potek SPI komunikacije. Da komunikacija deluje pravilno, sta potrebni dve nastavitvi, ki morata biti enaki na gospodarni in suženjski napravi, saj drugače lahko pride do napačne interpretacije podatkov.

Ti dve nastavitvi sta:

1. Nastavitev načina delovanja - to določa ali se bodo vrednosti bitov vzorčile na prehodu signala ure iz nizkega na visoko stanje ali obratno.

2. Vrstni red bitov - ta je lahko od najbolj pomembnega bita do najmanj pomembnega ali obratno. Na primer, če želimo po SPI liniji prenesti število 25, to pomeni, da bi pri nastavitvi »MSB najprej« (najbolj pomemben bit najprej) morali poslati bite v zaporedju: 00011001. V primeru nastavitve »LSB najprej« pa v zaporedju: 10011000.

(43)

Error! Use the Home tab to apply Naslov 2 to the text that you want to appear here. 43

Slika 4.4: Prikaz potek SPI komunikcaije [2]

Komunikacijo konfiguriramo s klicem funkcije init_SPI_device(), kjer se nastavijo vsi parametri SPI povezave - torej pini na procesorju, kjer se so priključene MISO MOSI in SCK linije, hitrost SPI povezave (v našem primeru 500K bitov na sekundo), način delovanja 0, kar pomeni, da je SCK linija aktivna na visokem nivoju, vzorčenje pa se zgodi ob prehodu SCK linije iz nizkega na visoko stanje in zaporedje bitov: najbolj pomemben najprej.

nrf_drv_spi_config_t spim_config = NRF_DRV_SPI_DEFAULT_CONFIG;

spim_config.ss_pin = NRF_DRV_SPI_PIN_NOT_USED; /** I will toggle SS pin by hand**/

spim_config.miso_pin = 13; //changed pin for BM50 spim_config.mosi_pin = 14; //changed pin for BM50 spim_config.sck_pin = 15; //changed pin for BM50

spim_config.irq_priority = SPI_DEFAULT_CONFIG_IRQ_PRIORITY;

spim_config.orc = 0xFF;

spim_config.frequency = NRF_DRV_SPI_FREQ_500K;

spim_config.mode = NRF_DRV_SPI_MODE_0; //3

spim_config.bit_order = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST;

(44)

Reference

POVEZANI DOKUMENTI

Kot splošno prepričanje velja, da so tako pridobljeni rezultati verodostojnejši kot rezultati, pridobljeni preko formalnega testiranja znanja, saj je za učence alternativna

The conference should foster the harvesting of new practices, approaches, projects, networks and create space for reflection, exchange of practice, presentation of results

V kolikor je končni uporabnik prijavil zahtevek za storitev preko self service portala, lahko skrbnik komunicira s končnim uporabnikom tako, da označi polje Viewable.. Klikne na

Cilj diplomske naloge je razvoj mikrokrmilne knjižnice za mikrokrmilno platformo Arduino UNO, ki bo opravljala komunikacijo preko serijskega vmesnika UART z brezžičnim modulom

 Dual SPI - pošiljanje podatkov je izvedeno kot izmenični prenos (ang. half duplex) dveh bitov tako, da je MOSI definiran kot IO0, in MISO pa IO1.  QUAD SPI – dodani sta še

 ima obsežno dokumentacijo, ki je na voljo tako preko spleta kot za delo brez povezave. Sencha Touch 2 prihaja v paketu z obsežnim seznamom komponent,

Poleg parametrov, ki so vezani na urin signal je potrebno za SPI prenos doloˇ citi ˇse dolˇ zino podatkov (8 ali 16 bitov), vrstni red poˇsiljanja bitov – ali naj se

lI$rrezen model za preprecevanje, lIpravljanje in razreseva nje konflikrov. V praksi so r e faze medsebojno povezane in se preplerojo tel' lahko potekajo celo vse