Rev Author Line No. Line
2943 poskozby 1 /*
2 ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
3  
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7  
8 http://www.apache.org/licenses/LICENSE-2.0
9  
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16  
17 #include "ch.h"
18 #include "hal.h"
19 #include "test.h"
20 #include "serial.h"
21 #include "gpt.h"
22 #include <string.h>
23 #include "keil/GPS_dekoduj.h"
24  
25 static void pwmpcb(PWMDriver *pwmp);
26 static void adccb(ADCDriver *adcp, adcsample_t *buffer, size_t n);
27  
28 /* Total number of channels to be sampled by a single ADC operation.*/
29 #define ADC_GRP1_NUM_CHANNELS 2
30  
31 /* Depth of the conversion buffer, channels are sampled four times each.*/
32 #define ADC_GRP1_BUF_DEPTH 4
33  
34 /*MAX delka prikazu, ktery uzivatel muze zadat*/
35 #define MAX_DELKA_PRIKAZU 10
36  
37 /*Velikost GPS bufferu*/
38 #define GPS_BUFFER 500
39  
40 extern NMEA_GPGGA GPGGA_informace;
41 Thread *tp_odpal = NULL;
42 /*
43 * ADC samples buffer.
44 */
45 static adcsample_t samples[ADC_GRP1_NUM_CHANNELS * ADC_GRP1_BUF_DEPTH];
46  
47 /*
48 * ADC conversion group.
49 * Mode: Linear buffer, 4 samples of 2 channels, SW triggered.
50 * Channels: IN10 (48 cycles sample time)
51 * Sensor (192 cycles sample time)
52 */
53 static const ADCConversionGroup adcgrpcfg = {
54 FALSE,
55 ADC_GRP1_NUM_CHANNELS,
56 adccb,
57 NULL,
58 /* HW dependent part.*/
59 0, /* CR1 */
60 ADC_CR2_SWSTART, /* CR2 */
61 0,
62 ADC_SMPR2_SMP_AN10(ADC_SAMPLE_48) | ADC_SMPR2_SMP_SENSOR(ADC_SAMPLE_192),
63 0,
64 ADC_SQR1_NUM_CH(ADC_GRP1_NUM_CHANNELS),
65 0,
66 0,
67 0,
68 ADC_SQR5_SQ2_N(ADC_CHANNEL_IN10) | ADC_SQR5_SQ1_N(ADC_CHANNEL_SENSOR)
69 };
70 /*
71 * Konfigurace USART2
72 */
73  
74 static const SerialConfig USART2_config =
75 {
76 /*Speed*/
77 9600,
78 /*Initialization value for the CR1 register.*/
79 0,
80 /*Initialization value for the CR2 register.*/
81 USART_CR2_STOP1_BITS | USART_CR2_LINEN,
82 /*Initialization value for the CR3 register.*/
83  
84 };
85 //GPTDriver GPTD2;
86 /*
87 * GPT2 callback.
88 */
89 static void gpt2cb(GPTDriver *gptp)
90 {
91 (void)gptp;
92 palTogglePad(GPIOB, GPIOB_LED4);
93 /* Wakes up the thread.*/
94 chSysLockFromIsr();
95 if (tp_odpal != NULL) {
96 //tp_odpal->p_u.rdymsg = (msg_t)55; /* Sending the message, optional.*/
97 chSchReadyI(tp_odpal);
98 tp_odpal = NULL;
99 }
100 chSysUnlockFromIsr();
101 }
102  
103 /*
104 *Konfigurace casovace 2
105 */
106 static const GPTConfig gpt2cfg =
107 {
108 1000, /*1000Hz f*/
109 gpt2cb /*callback fce*/
110 };
111  
112  
113  
114 /*
115 * PWM configuration structure.
116 * Cyclic callback enabled, channels 1 and 2 enabled without callbacks,
117 * the active state is a logic one.
118 */
119 static PWMConfig pwmcfg = {
120 10000, /* 10kHz PWM clock frequency. */
121 10000, /* PWM period 1S (in ticks). */
122 pwmpcb,
123 {
124 {PWM_OUTPUT_ACTIVE_HIGH, NULL},
125 {PWM_OUTPUT_ACTIVE_HIGH, NULL},
126 {PWM_OUTPUT_DISABLED, NULL},
127 {PWM_OUTPUT_DISABLED, NULL}
128 },
129 /* HW dependent part.*/
130  
131 };
132  
133 /*
134 * USART konfigurace
135 */
136  
137  
138 /*
139 * PWM cyclic callback.
140 * A new ADC conversion is started.
141 */
142 static void pwmpcb(PWMDriver *pwmp) {
143  
144 (void)pwmp;
145  
146 /* Starts an asynchronous ADC conversion operation, the conversion
147 will be executed in parallel to the current PWM cycle and will
148 terminate before the next PWM cycle.*/
149 chSysLockFromIsr();
150 adcStartConversionI(&ADCD1, &adcgrpcfg, samples, ADC_GRP1_BUF_DEPTH);
151 chSysUnlockFromIsr();
152 }
153  
154 /*
155 * ADC end conversion callback.
156 * The PWM channels are reprogrammed using the latest ADC samples.
157 * The latest samples are transmitted into a single SPI transaction.
158 */
159 void adccb(ADCDriver *adcp, adcsample_t *buffer, size_t n) {
160  
161 (void) buffer; (void) n;
162 /* Note, only in the ADC_COMPLETE state because the ADC driver fires an
163 intermediate callback when the buffer is half full.*/
164 if (adcp->state == ADC_COMPLETE) {
165 adcsample_t avg_ch1, avg_ch2;
166  
167 /* Calculates the average values from the ADC samples.*/
168 avg_ch1 = (samples[0] + samples[2] + samples[4] + samples[6]) / 4;
169 avg_ch2 = (samples[1] + samples[3] + samples[5] + samples[7]) / 4;
170  
171 chSysLockFromIsr();
172  
173 /* Changes the channels pulse width, the change will be effective
174 starting from the next cycle.*/
175 pwmEnableChannelI(&PWMD4, 0, PWM_FRACTION_TO_WIDTH(&PWMD4, 4096, avg_ch1));
176 pwmEnableChannelI(&PWMD4, 1, PWM_FRACTION_TO_WIDTH(&PWMD4, 4096, avg_ch2));
177  
178  
179 chSysUnlockFromIsr();
180 }
181 }
182  
183 /*
184 * Vlakno pro ovladani odpalovaci sekvence
185 */
186 static WORKING_AREA(waThread_odpal, 128);
187 static msg_t Thread_odpal(void *arg) {
188 uint8_t stav = 0; // rika, ve ktere fazi je odpalovani
189 (void)arg;
190 chRegSetThreadName("Odpal_vlakno");
191 while (TRUE)
192 {
193 //msg_t msg;
194  
195 /* Waiting for the IRQ to happen.*/
196 chSysLock();
197 tp_odpal = chThdSelf();
198 chSchGoSleepS(THD_STATE_SUSPENDED);
199 //msg = chThdSelf()->p_u.rdymsg; /* Retrieving the message, optional.*/
200 chSysUnlock();
201 /* Perform processing here.*/
202 switch (stav)
203 {
204 case 0: sdWrite(&SD1,"0",2);
205 break;
206 case 1: sdWrite(&SD1,"1",2);
207 break;
208 case 2: sdWrite(&SD1,"2",2);
209 break;
210 case 3: sdWrite(&SD1,"3",2);
211 break;
212 case 4: sdWrite(&SD1,"4",2);
213 break;
214 default: sdWrite(&SD1,"konec",6);
215 stav = 0;
216 break;
217 }
218  
219 stav++;
220 }
221 }
222  
223  
224 /*
225 * Vlakno pro obsluhu GPS prijimace
226 */
227 static WORKING_AREA(waThread_GPS, 768);
228 static msg_t Thread_GPS(void *arg) {
229 /*
230 * Nacita se jen nekolik NMEA zprav, aby se neplytvalo pameti na ulozeni kompletniho
231 * setu s tím rizikem, ze se nekdy nenacte aktualni informace o poloze.
232 */
233 uint8_t inBuffer[GPS_BUFFER];
234 char *zacatek_retezce;
235 char *konec_retezce;
236 uint8_t pocet_znaku;
237 uint8_t NMEA_zprava[100];
238  
239 (void)arg;
240 chRegSetThreadName("GPS_NMEA");
241 /*
242 * Activates the serial driver 2 using the driver default configuration.
243 * PA2 and PA3 are routed to USART2.
244 */
245  
246 sdStart(&SD2, &USART2_config);
247 palSetPadMode(GPIOA, 2, PAL_MODE_ALTERNATE(7)); //TX
248 palSetPadMode(GPIOA, 3, PAL_MODE_ALTERNATE(7)); //RX
249  
250  
251 while (TRUE) {
252 chThdSleepMilliseconds(1000); //neni potreba data vycitat rychleji
253 sdRead(&SD2,inBuffer,GPS_BUFFER);
254  
255 /*
256 *Nejprve se vycte cast NMEA dat, pote se vyhleda retezec GPGGA zpravy, ta se vyparsuje a pomoci fce
257 *dekoduj_zpravu_GPS, ktera vyparsuje data o poloze a jine, a ulozi je do struktury GPGGA_informace.
258 */
259  
260 if ((zacatek_retezce = strstr((char *)inBuffer,"$GPGGA")) != NULL)
261 {
262 if ((konec_retezce = strstr(zacatek_retezce,"*")) != NULL)
263 {
264 pocet_znaku = (konec_retezce-zacatek_retezce)/sizeof(char);
265 if (pocet_znaku > 100)
266 {
267 pocet_znaku = 100;
268 }
269 strncpy((char *)NMEA_zprava,zacatek_retezce,pocet_znaku);
270 dekoduj_zpravu_GPS(&NMEA_zprava[0],pocet_znaku);
271 sdWrite(&SD2,"Latitude: ",sizeof("Latitude: ")/sizeof(char));
272 sdWrite(&SD2,GPGGA_informace.Latitude,sizeof(GPGGA_informace.Latitude)/sizeof(uint8_t));
273 sdWrite(&SD2,"\r\n",2);
274 sdWrite(&SD2,"Longitude: ",sizeof("Longitude: ")/sizeof(char));
275 sdWrite(&SD2,GPGGA_informace.Longitude,sizeof(GPGGA_informace.Longitude)/sizeof(uint8_t));
276 sdWrite(&SD2,"\r\n",2);
277 sdWrite(&SD2,"Altitude: ",sizeof("Altitude: ")/sizeof(char));
278 sdWrite(&SD2,GPGGA_informace.Altitude,sizeof(GPGGA_informace.Altitude)/sizeof(uint8_t));
279 sdWrite(&SD2,"\r\n",2);
280 sdWrite(&SD2,"Status: ",sizeof("Status: ")/sizeof(char));
281 sdWrite(&SD2,&GPGGA_informace.Status_GPS,sizeof(GPGGA_informace.Status_GPS)/sizeof(uint8_t));
282 sdWrite(&SD2,"\r\n",2);
283 sdWrite(&SD2,NMEA_zprava,pocet_znaku);
284 sdWrite(&SD2,"\r\n",2);
285 }
286 else
287 {
288 sdWrite(&SD2,"\r\n",2);
289 sdWrite(&SD2,"Nenalezen ukoncovaci znak NMEA zpravy *",sizeof("Nenalezen ukoncovaci znak NMEA zpravy *")/sizeof(char));
290 sdWrite(&SD2,inBuffer,GPS_BUFFER);
291 sdWrite(&SD2,"\r\n",2);
292 }
293 }
294 else
295 sdWrite(&SD2,"Nenalezen zacatek GPGGA zpravy",sizeof("Nenalezen zacatek GPGGA zpravy")/sizeof(char));
296  
297 }
298 }
299  
300 /*
301 * This is a periodic thread that does absolutely nothing except increasing
302 * a seconds counter.
303 */
304 static WORKING_AREA(waThread1, 128);
305 static msg_t Thread1(void *arg) {
306 static uint32_t seconds_counter;
307  
308 (void)arg;
309 chRegSetThreadName("counter");
310 while (TRUE) {
311 chThdSleepMilliseconds(1000);
312 seconds_counter++;
313 }
314 }
315  
316 void dekodujPrikaz(char *prikaz)
317 {
318 //int8_t porov;
319 //porov = strcmp(prikaz,"ahoj");
320 if(strcmp(prikaz,"ahoj") == 0)
321 {
322 palTogglePad(GPIOB, GPIOB_LED4);
323 }
324 else if (strcmp(prikaz,"zdar") == 0)
325 {
326 palTogglePad(GPIOB, GPIOB_LED3);
327 }
328 else
329 {
330 uint8_t zp_neplatny[] = "Neplatny prikaz, spravny format *<prikaz>\n\r";
331 sdWrite(&SD1,zp_neplatny,sizeof(zp_neplatny)/sizeof(uint8_t));
332 palTogglePad(GPIOB, GPIOB_LED3);
333 }
334 }
335  
336  
337  
338 /*
339 * Application entry point.
340 */
341 int main(void) {
342 uint8_t znaky[20];
343 char prikaz[MAX_DELKA_PRIKAZU + 1];
344 uint8_t uk_pri = 0;
345 uint8_t zapis = 0; // pokud je prijata '*', zacina se s rozpoznanim prikazu az do '\n'
346  
347 /*
348 * System initializations.
349 * - HAL initialization, this also initializes the configured device drivers
350 * and performs the board-specific initializations.
351 * - Kernel initialization, the main() function becomes a thread and the
352 * RTOS is active.
353 */
354 halInit();
355 chSysInit();
356  
357 /*
358 * Activates the serial driver 1 using the driver default configuration.
359 * PA9 and PA10 are routed to USART1.
360 */
361 sdStart(&SD1, NULL);
362 palSetPadMode(GPIOA, 9, PAL_MODE_ALTERNATE(7));
363 palSetPadMode(GPIOA, 10, PAL_MODE_ALTERNATE(7));
364  
365 //gptObjectInit(&GPTD2);
366 /*
367 * aktivuje timer2 a prejde tak do aktivniho stavu
368 */
369 gptStart(&GPTD2,&gpt2cfg);
370  
371 /*
372 * If the user button is pressed after the reset then the test suite is
373 * executed immediately before activating the various device drivers in
374 * order to not alter the benchmark scores.
375 */
376 if (palReadPad(GPIOA, GPIOA_BUTTON))
377 TestThread(&SD1);
378  
379 /*
380 * Initializes the SPI driver 2. The SPI2 signals are routed as follow:
381 * PB12 - NSS.
382 * PB13 - SCK.
383 * PB14 - MISO.
384 * PB15 - MOSI.
385 */
386 palSetPad(GPIOB, 12);
387 palSetPadMode(GPIOB, 12, PAL_MODE_OUTPUT_PUSHPULL |
388 PAL_STM32_OSPEED_HIGHEST); /* NSS. */
389 palSetPadMode(GPIOB, 13, PAL_MODE_ALTERNATE(5) |
390 PAL_STM32_OSPEED_HIGHEST); /* SCK. */
391 palSetPadMode(GPIOB, 14, PAL_MODE_ALTERNATE(5)); /* MISO. */
392 palSetPadMode(GPIOB, 15, PAL_MODE_ALTERNATE(5) |
393 PAL_STM32_OSPEED_HIGHEST); /* MOSI. */
394  
395 /*
396 * Initializes the ADC driver 1 and enable the thermal sensor.
397 * The pin PC0 on the port GPIOC is programmed as analog input.
398 */
399 adcStart(&ADCD1, NULL);
400 adcSTM32EnableTSVREFE();
401 palSetPadMode(GPIOC, 0, PAL_MODE_INPUT_ANALOG);
402  
403 /*
404 * Initializes the PWM driver 4, routes the TIM4 outputs to the board LEDs.
405 */
406 pwmStart(&PWMD4, &pwmcfg);
407 //palSetPadMode(GPIOB, GPIOB_LED4, PAL_MODE_ALTERNATE(2));
408 palSetPadMode(GPIOB, GPIOB_LED3, PAL_MODE_ALTERNATE(2));
409 /*
410 * Zelena led aktivace portu
411 */
412  
413 palSetPadMode(GPIOB, GPIOB_LED4, PAL_MODE_OUTPUT_PUSHPULL);
414 palSetPadMode(GPIOB, GPIOB_LED3, PAL_MODE_OUTPUT_PUSHPULL);
415 //test_println("ahoj");
416 /*sdRead(&SD1,znaky,5);
417 sdWrite(&SD1,"\n",1);
418 sdWrite(&SD1,znaky,2);
419 palWritePad(GPIOB, GPIOB_LED4, PAL_HIGH);
420 */
421 /*
422 * Creates the example thread.
423 */
424 chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL);
425  
426 /*
427 * Vytvori vlakno pro prijem dat z GPS modulu
428 */
429 chThdCreateStatic(waThread_GPS, sizeof(waThread_GPS), NORMALPRIO, Thread_GPS, NULL);
430 /*
431 * Vytvori vlakno pro odpalovaci sekvenci
432 */
433 (void)chThdCreateStatic (waThread_odpal, sizeof(waThread_odpal), NORMALPRIO, Thread_odpal, NULL);
434  
435  
436 /*
437 * Normal main() thread activity, in this demo it does nothing except
438 * sleeping in a loop and check the button state, when the button is
439 * pressed the test procedure is launched with output on the serial
440 * driver 1.
441 */
442 gptStartContinuous(&GPTD2,1000);
443 while (TRUE) {
444  
445 sdRead(&SD1,znaky,1);
446 /*Kdyz uzivatel stiskne enter -> dekoduj a vykonej prikaz*/
447 if (znaky[0] == '\r')
448 {
449 uk_pri = 0;
450 zapis = 0;
451 dekodujPrikaz(prikaz);
452 prikaz[0] = 0;
453 }
454 /*Uklada prikaz*/
455 if (zapis == 1 && uk_pri < MAX_DELKA_PRIKAZU)
456 {
457 prikaz[uk_pri++] = znaky[0];
458 prikaz[uk_pri + 1] = 0;
459 }
460 /*Pokud je prikaz delsi, nez by mel byt, prestane ukladat a upozorni uzivatele*/
461 else if (zapis == 1 && uk_pri == MAX_DELKA_PRIKAZU)
462 {
463 uk_pri = 0;
464 zapis = 0;
465 dekodujPrikaz(prikaz);
466 }
467 /*Uzivatel zacal zadavat prikaz*/
468 if(znaky[0] == '*' && zapis == 0)
469 zapis = 1;
470  
471  
472 if (palReadPad(GPIOA, GPIOA_BUTTON))
473  
474 TestThread(&SD1);
475 chThdSleepMilliseconds(500);
476 }
477 }