Zde můžete vidět rozdíly mezi vybranou verzí a aktuální verzí dané stránky.
Obě strany předchozí revize Předchozí verze Následující verze | Předchozí verze | ||
2014:pixel-light [2015/01/16 21:54] Pavel Kostelník |
2014:pixel-light [2015/01/19 01:44] (aktuální) Pavel Kostelník |
||
---|---|---|---|
Řádek 65: | Řádek 65: | ||
__task void init (void) | __task void init (void) | ||
{ | { | ||
- | // create tasks: | + | // create tasks: |
- | t_blink = os_tsk_create(blink, 0); | + | t_blink = os_tsk_create(blink, 0); |
- | t_uart_tx = os_tsk_create(uart_tx, 0); | + | t_uart_tx = os_tsk_create(uart_tx, 0); |
- | t_interpreter = os_tsk_create(interpreter, 0); | + | t_interpreter = os_tsk_create(interpreter, 0); |
- | t_spi247 = os_tsk_create(spi247, 0); | + | t_spi247 = os_tsk_create(spi247, 0); |
- | t_spi787 = os_tsk_create(spi787, 0); | + | t_spi787 = os_tsk_create(spi787, 0); |
- | t_dc247 = os_tsk_create(dc247, 0); | + | t_dc247 = os_tsk_create(dc247, 0); |
- | // init semaphores: | + | // init semaphores: |
- | os_sem_init (&Semspi247, 0); | + | os_sem_init (&Semspi247, 0); |
- | os_sem_init (&Semspi787, 0); | + | os_sem_init (&Semspi787, 0); |
- | os_sem_init (&Semdc247, 0); | + | os_sem_init (&Semdc247, 0); |
- | // init mutexes | + | // init mutexes |
- | os_mut_init(&Mutspi247); | + | os_mut_init(&Mutspi247); |
- | os_mut_init(&Mutspi787); | + | os_mut_init(&Mutspi787); |
- | os_mut_init(&Mutuart_tx); | + | os_mut_init(&Mutuart_tx); |
- | //delete itself: | + | // delete itself: |
- | os_tsk_delete_self (); | + | os_tsk_delete_self (); |
} | } | ||
//------------------------- TASK: init -- (End) ---------------------------------- | //------------------------- TASK: init -- (End) ---------------------------------- | ||
</code> | </code> | ||
+ | |||
=== TASK: blink === | === TASK: blink === | ||
Řádek 94: | Řádek 95: | ||
//-------------------------- TASK: blink -- (Begin) --------------------------------- | //-------------------------- TASK: blink -- (Begin) --------------------------------- | ||
// Blinking with LED D5 | // Blinking with LED D5 | ||
- | __task void blink (void) | + | __task void blink (void) |
{ | { | ||
- | while(1) | + | while(1) |
- | { | + | { |
- | LED_off(5); // turn off LED5 | + | LED_off(5); // turn off LED5 |
- | os_dly_wait (500); // wait for 500 ms | + | os_dly_wait (500); // wait for 500 ms |
- | LED_on(5); // turn on LED5 | + | LED_on(5); // turn on LED5 |
- | os_dly_wait (500); // wait for 500 ms | + | os_dly_wait (500); // wait for 500 ms |
- | } | + | } |
} | } | ||
//-------------------------- TASK: blink -- (End) ---------------------------------- | //-------------------------- TASK: blink -- (End) ---------------------------------- | ||
</code> | </code> | ||
+ | |||
=== TASK: interpreter, spi787, spi247, dc247 === | === TASK: interpreter, spi787, spi247, dc247 === | ||
Task interpreter přebírá přijatá data po lince UART z počítače a dále je třídí na základě požadované operace, případně danou operaci sám provede. Například pokud je požadována operace komunikace po SPI s obvodem zdroje, task interpreter pošle data do příslušného bufferu a zašle semafor tasku spi787, kterého tím odblokuje, a task spi787 vykoná příkaz, který mu byl předán příslušným bufferem. Po vykonání příkazu task spi787 odešle výsledná data do počítače přes UART linku tím, že přepošle data tasku uart_tx, který se postará o jejich korektní odeslání. | Task interpreter přebírá přijatá data po lince UART z počítače a dále je třídí na základě požadované operace, případně danou operaci sám provede. Například pokud je požadována operace komunikace po SPI s obvodem zdroje, task interpreter pošle data do příslušného bufferu a zašle semafor tasku spi787, kterého tím odblokuje, a task spi787 vykoná příkaz, který mu byl předán příslušným bufferem. Po vykonání příkazu task spi787 odešle výsledná data do počítače přes UART linku tím, že přepošle data tasku uart_tx, který se postará o jejich korektní odeslání. | ||
- | Ukázka jednoho tasku je uvedena zde: | ||
- | |||
- | <code c> | ||
- | //------------------------- TASK: spi247 -- (Begin) -------------------------------- | ||
- | // SPI communication with pixel light | ||
- | __task void spi247 (void) | ||
- | { | ||
- | while(1) | ||
- | { | ||
- | os_sem_wait(&Semspi247, 0xFFFF); // wait for data (driven by semaphore) | ||
- | SPI247_ReadBuff = (SPI247_ReadBuff+1) & (BUFFERSPISIZE - 1); | ||
- | os_mut_wait(&Mutspi247, 0xFFFF); // wait for mutex | ||
- | SPI_SendFrame((SPI247_Buffer[SPI247_ReadBuff][0] & 0x07), 0, SPI247_Buffer[SPI247_ReadBuff][1], SPI247_Buffer[SPI247_ReadBuff][2], | ||
- | SPI247_Buffer[SPI247_ReadBuff][3], SPI247_Buffer[SPI247_ReadBuff][4]); // send SPI frame | ||
- | while ((LPC_SSP2->SR & 0x4)== 0x0){} // wait until first SPI frame is received | ||
- | SPI_RcvData = LPC_SSP2->DR; // received SPI frame | ||
- | SPI_RcvData = SPI_RcvData << 16; // shift first received SPI frame (higher) | ||
- | while ((LPC_SSP2->SR & 0x4)== 0x0){} // wait until second SPI frame is received | ||
- | SPI_RcvData = SPI_RcvData + (LPC_SSP2->DR & 0x0000FFFF); // add lower received SPI frame | ||
- | |||
- | os_mut_wait(&Mutuart_tx, 0xFFFF); // wait for mutex | ||
- | UART_SendFrame (0x01); // send identification frame to PC | ||
- | UART_SendFrame (SPI247_Buffer[SPI247_ReadBuff][0]); // send target device | ||
- | UART_SendFrame (SPI_RcvData&0xFF); // send 1. byte (lowest) | ||
- | UART_SendFrame ((SPI_RcvData >> 8)&0xFF); // send 2. byte | ||
- | UART_SendFrame ((SPI_RcvData >> 16)&0xFF); // send 3. byte | ||
- | UART_SendFrame ((SPI_RcvData >> 24)&0xFF); // send 4. byte (highest) | ||
- | os_mut_release(&Mutuart_tx); // release mutex | ||
- | |||
- | SPI_SendFrame((SPI247_Buffer[SPI247_ReadBuff][0] & 0x07), 0, (SPI247_Buffer[SPI247_ReadBuff][1] & 0xF0) + 0x0F, 0, 0, 0); | ||
- | while ((LPC_SSP2->SR & 0x4)== 0x0){} // wait until first SPI frame is received | ||
- | SPI_RcvData = LPC_SSP2->DR; // received SPI frame | ||
- | SPI_RcvData = SPI_RcvData << 16; // shift first received SPI frame (higher) | ||
- | while ((LPC_SSP2->SR & 0x4)== 0x0){} // wait until second SPI frame is received | ||
- | SPI_RcvData = SPI_RcvData + (LPC_SSP2->DR & 0x0000FFFF); // add lower received SPI frame | ||
- | |||
- | if (((SPI247_Buffer[SPI247_ReadBuff][1]&0x0F) < 12)) | ||
- | { | ||
- | if(((SPI_RcvData&0xFF) == SPI247_Buffer[SPI247_ReadBuff][2]) && (((SPI_RcvData>>8)&0xFF) == SPI247_Buffer[SPI247_ReadBuff][3]) && | ||
- | (((SPI_RcvData>>16)&0xFF) == SPI247_Buffer[SPI247_ReadBuff][4])) | ||
- | temp++; | ||
- | } | ||
- | |||
- | if((SPI247_Buffer[SPI247_ReadBuff][1] & 0x0F) == 0x0C) // write to control register? | ||
- | { | ||
- | if ((SPI247_Buffer[SPI247_ReadBuff][2] & 0x05) == 0x05) // write to MAPENA? | ||
- | { | ||
- | while ((SPI_RcvData&0x05) == 5) // wait for MAPENA | ||
- | { | ||
- | SPI_SendFrame((SPI247_Buffer[SPI247_ReadBuff][0] & 0x07), 0, SPI247_Buffer[SPI247_ReadBuff][1], SPI247_Buffer[SPI247_ReadBuff][2], | ||
- | SPI247_Buffer[SPI247_ReadBuff][3], SPI247_Buffer[SPI247_ReadBuff][4]); // send SPI frame | ||
- | while ((LPC_SSP2->SR & 0x4)== 0x0){} // wait until first SPI frame is received | ||
- | SPI_RcvData = LPC_SSP2->DR; // received SPI frame | ||
- | SPI_RcvData = SPI_RcvData << 16; // shift first received SPI frame (higher) | ||
- | while ((LPC_SSP2->SR & 0x4)== 0x0){} // wait until second SPI frame is received | ||
- | SPI_RcvData = SPI_RcvData + (LPC_SSP2->DR & 0x0000FFFF); // add lower received SPI frame | ||
- | |||
- | } | ||
- | } | ||
- | } | ||
- | os_mut_release(&Mutspi247); // release mutex | ||
- | } // end of while(1) | ||
- | } | ||
- | //------------------------- TASK: spi247 -- (End) ---------------------------------- | ||
- | </code> | ||
=== TASK: wb, dz, bl === | === TASK: wb, dz, bl === | ||
- | Dále software obsahuje tři dočasné tasky, které se vytváří a mažou dynamicky v případě, že je daný efekt potřeba. Například pokud přijde z počítače povel pro efekt Dark Zone, task interpreter vytvoří nový task dz, který se už sám stará o odesílání příslušných dat do SPI periferie. Task s efektem se maže opět příkazem z počítače. V jednu chvíli je možné mít spuštěných i více kopií stejného tasku, které obsluhují různé obvody integrovaného budiče. | + | Dále software obsahuje tři dočasné tasky, které se vytváří a mažou dynamicky v případě, že je daný efekt potřeba. Konkrétně jsou implementovány funkce Wiping Blinker, Dark Zone a Bending Light. Například pokud přijde z počítače povel pro efekt Dark Zone, task interpreter vytvoří nový task dz, který se už sám stará o odesílání příslušných dat do SPI periferie. Task s efektem se maže opět příkazem z počítače. V jednu chvíli je možné mít spuštěných i více kopií stejného tasku, které obsluhují různé obvody integrovaného budiče. |
Ukázka jednoho tasku je uvedena zde: | Ukázka jednoho tasku je uvedena zde: | ||
<code c> | <code c> | ||
Řádek 183: | Řádek 120: | ||
__task void wb (void) | __task void wb (void) | ||
{ | { | ||
- | uint8_t target = newtarget; // target device | + | uint8_t target = newtarget; // target device |
- | float wb_dt = 0; // time difference | + | float wb_dt = 0; // time difference |
- | while(1) | + | while(1) |
- | { | + | { |
- | wb_dt = (float)(wb_stop[target] - wb_start[target])/12.0; | + | wb_dt = (float)(wb_stop[target] - wb_start[target])/12.0; |
- | if (wb_counter[target] >= wb_per[target]) // counter overflow | + | if (wb_counter[target] >= wb_per[target]) // counter overflow |
- | wb_counter[target] = 0; | + | wb_counter[target] = 0; |
- | else | + | else |
- | wb_counter[target]++; // increment counter | + | wb_counter[target]++; // increment counter |
- | if (wb_counter[target] < wb_start[target]) // all LEDs OFF | + | if (wb_counter[target] < wb_start[target]) // all LEDs OFF |
- | { | + | { |
- | for (i=0; i<12; i++) | + | for (i=0; i<12; i++) |
- | { | + | { |
- | DCs[i] = 1023; | + | DCs[i] = 1023; |
- | } | + | } |
- | j=0; | + | j=0; |
- | } | + | } |
- | else if (wb_counter[target] < wb_stop[target]) //all LEDs dimmed | + | else if (wb_counter[target] < wb_stop[target]) //all LEDs dimmed |
- | { | + | { |
- | for (i=0; i<12; i++) | + | for (i=0; i<12; i++) |
- | { | + | { |
- | if (wb_counter[target] < (wb_start[target] + i*wb_dt)) | + | if (wb_counter[target] < (wb_start[target] + i*wb_dt)) |
- | DCs[i] = 1023; | + | DCs[i] = 1023; |
- | else if (wb_counter[target] < (wb_start[target] + (i+1)*wb_dt)) | + | else if (wb_counter[target] < (wb_start[target] + (i+1)*wb_dt)) |
- | DCs[i] = (wb_start[target] + (i+1)*wb_dt - wb_counter[target])/wb_dt*1023; | + | DCs[i] = (wb_start[target] + (i+1)*wb_dt - wb_counter[target])/wb_dt*1023; |
- | else | + | else |
- | DCs[i] = 0; | + | DCs[i] = 0; |
- | } | + | } |
- | } | + | } |
- | else // all LEDs ON | + | else // all LEDs ON |
- | { | + | { |
- | for (i=0; i<12; i++) | + | for (i=0; i<12; i++) |
- | { | + | { |
- | DCs[i] = 0; | + | DCs[i] = 0; |
- | } | + | } |
- | } | + | } |
- | dimming(DCs, LEDcount, ON, OFF, TR, lastLevel[target]); // ON, OFF, TR values computation using Dimming algorithm | + | dimming(DCs, LEDcount, ON, OFF, TR, lastLevel[target]); // ON, OFF, TR values computation using Dimming algorithm |
- | os_mut_wait(&Mutspi247, 0xFFFF); // wait for mutex | + | os_mut_wait(&Mutspi247, 0xFFFF); // wait for mutex |
- | SPI_SendFrame(target + 3, 1, 0xCF, 0, 0, 0); // send SPI frame to pixel light | + | SPI_SendFrame(target + 3, 1, 0xCF, 0, 0, 0); // send SPI frame to pixel light |
- | while ((LPC_SSP2->SR & 0x4)== 0x0){} // wait until frame is received | + | while ((LPC_SSP2->SR & 0x4)== 0x0){} // wait until frame is received |
- | SPI_RcvData = (LPC_SSP2->DR)<<16; // shift received data | + | SPI_RcvData = (LPC_SSP2->DR)<<16; // shift received data |
- | while ((LPC_SSP2->SR & 0x4)== 0x0){} // wait until frame is received | + | while ((LPC_SSP2->SR & 0x4)== 0x0){} // wait until frame is received |
- | SPI_RcvData += LPC_SSP2->DR; // sum received data | + | SPI_RcvData += LPC_SSP2->DR; // sum received data |
- | SPI_SendFrame(target + 3, 1, 0xCC, ((SPI_RcvData)&(0xFB)), (SPI_RcvData>>8)&0xFF, (SPI_RcvData>>16)&0xFF); | + | SPI_SendFrame(target + 3, 1, 0xCC, ((SPI_RcvData)&(0xFB)), (SPI_RcvData>>8)&0xFF, (SPI_RcvData>>16)&0xFF); |
- | while ((LPC_SSP2->SR & 0x4)== 0x0){} // wait until frame is received | + | while ((LPC_SSP2->SR & 0x4)== 0x0){} // wait until frame is received |
- | SPI_RcvData = (LPC_SSP2->DR)<<16; // shift received data | + | SPI_RcvData = (LPC_SSP2->DR)<<16; // shift received data |
- | while ((LPC_SSP2->SR & 0x4)== 0x0){} // wait until frame is received | + | while ((LPC_SSP2->SR & 0x4)== 0x0){} // wait until frame is received |
- | SPI_RcvData += LPC_SSP2->DR; // sum received data | + | SPI_RcvData += LPC_SSP2->DR; // sum received data |
- | for(i=0; i<12; i++) // send ON, OFF and TR values to pixel light | + | for(i=0; i<12; i++) // send ON, OFF and TR values to pixel light |
- | { | + | { |
- | SPI_SendFrame(target + 3, 1, i + 0xC0, ((OFF[i]<<4)+TR[i])&0xFF, ((ON[i]<<6)+(OFF[i]>>4))&0xFF, (ON[i]>>2)&0xFF); | + | SPI_SendFrame(target + 3, 1, i + 0xC0, ((OFF[i]<<4)+TR[i])&0xFF, ((ON[i]<<6)+(OFF[i]>>4))&0xFF, (ON[i]>>2)&0xFF); |
- | while ((LPC_SSP2->SR & 0x4)== 0x0){} // wait until frame is received | + | while ((LPC_SSP2->SR & 0x4)== 0x0){} // wait until frame is received |
- | SPI_RcvData = (LPC_SSP2->DR)<<16; // shift received data | + | SPI_RcvData = (LPC_SSP2->DR)<<16; // shift received data |
- | while ((LPC_SSP2->SR & 0x4)== 0x0){} // wait until frame is received | + | while ((LPC_SSP2->SR & 0x4)== 0x0){} // wait until frame is received |
- | SPI_RcvData += LPC_SSP2->DR; // sum received data | + | SPI_RcvData += LPC_SSP2->DR; // sum received data |
- | } | + | } |
- | SPI_SendFrame(target + 3, 1, 0xCC, ((SPI_RcvData)&0xFF)|(1<<2), (SPI_RcvData>>8)&0xFF, (SPI_RcvData>>16)&0xFF); //set MAPENA bit | + | SPI_SendFrame(target + 3, 1, 0xCC, ((SPI_RcvData)&0xFF)|(1<<2), (SPI_RcvData>>8)&0xFF, (SPI_RcvData>>16)&0xFF); //set MAPENA bit |
- | while ((LPC_SSP2->SR & 0x4)== 0x0){} // wait until frame is received | + | while ((LPC_SSP2->SR & 0x4)== 0x0){} // wait until frame is received |
- | SPI_RcvData = (LPC_SSP2->DR)<<16; // shift received data | + | SPI_RcvData = (LPC_SSP2->DR)<<16; // shift received data |
- | while ((LPC_SSP2->SR & 0x4)== 0x0){} // wait until frame is received | + | while ((LPC_SSP2->SR & 0x4)== 0x0){} // wait until frame is received |
- | SPI_RcvData += LPC_SSP2->DR; // sum received data | + | SPI_RcvData += LPC_SSP2->DR; // sum received data |
- | os_mut_release(&Mutspi247); // release mutex | + | os_mut_release(&Mutspi247); // release mutex |
- | os_dly_wait(20); | + | os_dly_wait(20); |
- | } // end while(1) | + | } // end while(1) |
} | } | ||
//--------------------------- TASK: wb -- (End) ----------------------------------- | //--------------------------- TASK: wb -- (End) ----------------------------------- | ||
</code> | </code> | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | ==== Návrh na úpravy ==== | ||
+ | Operační systém reálného času RTX je komplexní a velmi rozsáhlý nástroj, proto bez větších zkušeností je velký problém využít všechny jeho možnosti a vytvořit dobře optimalizovaný program. Taky proto byl kladen důraz na jednoduchost a využití pouze základních možností RTX, aby nedošlo k zamotání do různých funkcí a možností. Mezi další možnosti, které systém RTX podporuje, jsou mailboxy, signály a události, tak by jistě stálo za zvážení, zda by programu pomohly. | ||
+ | |||
+ | ===== Ukázka funkce ===== | ||
+ | |||
+ | {{youtube>keJ7lECmeH4?medium}} | ||
+ | |||
+ | ===== Zdrojové soubory ===== | ||
+ | Zdrojová data nejsou z důvodu ochrany duševního vlastnictví společnosti ON Semiconductor zcela zveřejněna. V rámci zdrojových souborů je možné najít nastavení RTX souborem RTX_Conf_CM.c. Dále jsou ve zdrojovém souboru main.c zveřejněny všechny tasky a jejich provázání, pouze pár menších částí bylo vyjmuto, které ale nemají vliv na fungování RTOS. Dále je v přiloženém balíku zveřejněno schéma desky s mikrokontrolérem. {{:2014:pixel-light:mpoa_pixellight.zip|}} | ||
+ | |||
+ | | ||
+ | ===== Závěr ===== | ||
+ | Naprogramovaný software je plně funkční, což je možné vidět i na ukázkovém videu níže. Nastavené časové údaje u ukázkových funkcí odpovídají skutečnosti, a proto je možné tvrdit, že časování v RTOS funguje podle požadavků. V softwaru je navíc implementovaná kontrola přetečení zásobníků jednotlivých tasků. Při testování softwaru bylo ověřeno, že aktuálně nastavená hodnota velikosti zásobníků 512 B je dostatečná. |