Other Parts Discussed in Thread: CC1310, BOOSTXL-TLV8544PIR
Tool/software: TI-RTOS
Hey guys,
I use the CC1310 Launchpad and BOOSTXL-TLV8544PIR Sensor with the TIDA-00489 Firmware and it basically works. But I am facing some issues and a I have a few questions, since I want to make a few changes to the code. As a sniffer, I am ussing SmartRF Studio with another CC1310 Launchpad.
Issues:
- I think there is a loose connection between the PIR-shield and the launchpad, making the device sometimes detect and send motions. I will make a few tests on the cpnnection when I have access to some testing devices, but has this been noticed more frequently before? (it only works, if windows gives me the sound like if I have connected some USB device)
- I use "puts" to write some stuff to the console. This only works once in the code. You got any idea why? (the code is below)
- I am facing some really strange behaviour regarding when a motion is detected and transmitted via sub GHz.
- Sometimes the movement is indicated immediately by sending AA, than FF and then 55 (55 is send after the comparators are both low again) and then further package/s is/are send 8-10s later indicating a movement which does not happen.
- Sometimes while I make movements no packages are send, but again 8-10s later they come, although there was no further movement.
--> Any idea, why there is sometimes such a big delay?
4. When I set PIR_QUIET_TIME to 5s, and I constantly make movements 15s long, I see that FF is send like ~20s after AA, like it should. But I don't understand why there are no further AA-packages send after the first detected movement?!
Software changes:
- I want to change the program flow, counting the movements and send them after 1min. Therefore, I want to keep the Hwi for detecting the movements and I want to add the Swi to send the #movements each minute. Can you help me create another clock to realize the Swi?
- Do you think a Task is better than a Swi for my purpose?
- Regarding issue #4 I hope you can help me, because I guess, that the counter won't work, if send_package(AA) does not work either...
- What happens to my "move" variable, which I use for counting, when the system goes to sleep, will it stay 0 or will there be some randoom number if I dont initialize it after every wakeup?
This are a lot of questions, but I really want to understand the setup, so that I will be able to use the TIDA-Board properly when I will get it.
Here is the code:
/* * Copyright (c) 2015, Texas Instruments Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /***** Includes *****/ #include <stdio.h> #include <stdlib.h> #include <xdc/std.h> #include <xdc/cfg/global.h> #include <xdc/runtime/System.h> #include <ti/sysbios/BIOS.h> #include <ti/sysbios/knl/Task.h> #include <ti/sysbios/knl/Clock.h> #include <ti/sysbios/knl/Semaphore.h> /* Drivers */ #include <ti/drivers/rf/RF.h> #include <ti/drivers/PIN.h> #include <ti/sysbios/family/arm/cc26xx/Power.h> #include <ti/sysbios/family/arm/cc26xx/PowerCC2650.h> #include <ti/drivers/I2C.h> #include <ti/drivers/PIN.h> #include <ti/drivers/pin/PINCC26XX.h> #include <driverlib/sys_ctrl.h> #include <TIDA-00489_Board.h> /* Board Header files */ #include "smartrf_settings/cc13xx_smartrf_settings.h" /***** Defines *****/ #define PIR_SETTLE_TIME 5000000 // 5 seconds //#define PIR_SETTLE_TIME 30000000 // 30 seconds (2 minutes) , sollte man so lassen, Einschwingzeit beim Einschalten //#define PIR_QUIET_TIME 10000000 // 10 seconds #define PIR_QUIET_TIME 5000000 // 20 seconds (1 minutes), das hier müsste wohl ganz runter auf 1s #define PIR_SHUTDOWN_TIME 1000000 // 1 seconds (5 Seconds), beschreibt wie lange er wartet bevor er nach dem Senden in den Sleep geht #define TX_TASK_STACK_SIZE 1024 // Each task stack must be large enough to handle both its normal function calls and two full interrupting Hwi contexts. #define TX_TASK_PRIORITY 2 // Defines the priority of the task. Higher priority (3>2) causes preference. /* TX Configuration */ #define PAYLOAD_LENGTH 3 // Vermutlich Angabe in Bytes und betrifft Packetgröße beim Senden #define PACKET_INTERVAL 4000000*0.001f // Setzt das Intervall auf 1ms, denn f = die Frequenz des Prozessors (=4MHz=250ns) /* Move limit*/ #define MOVE_LIMIT 10 //Anzahl ab wann der Sensor die Daten schicken soll; /***** Prototypes *****/ //<-- sagen dem Compiler welche Funktionen ihn im Programm erwarten static void txTaskFunction(UArg arg0, UArg arg1); // Diese Funktion beinhaltet den kompletten Sende- und Interruptprozess static void initializeTask(void); // Die Clock für die Übertragung und die Semaphore werden initialisiert static void radioSyncTxClockCallback(UArg a0); // Die Semaphore wird um einen Wert inkrementiert static void sendPacket(uint8_t data); // Behandelt explizit den Sendevorgang void intr_HwiFxn(PIN_Handle hPin, PIN_Id pinId); // Behandelt den Interrupt Pin /***** Variable declarations *****/ // Variablen werden deklariert static Task_Params txTaskParams; static Task_Struct txTask; static uint8_t txTaskStack[TX_TASK_STACK_SIZE]; static RF_Object rfObject; static RF_Handle rfHandle; static RF_Params rfParams; static Semaphore_Struct radioSyncTxSem; static Semaphore_Handle radioSyncTxSemHandle; static Clock_Struct radioSyncTxClock; static Clock_Handle radioSyncTxClockHandle; static uint8_t packet[PAYLOAD_LENGTH]; static uint8_t move; // von mir definiert /* Wake-up pin table */ // Die genannten Pins werden Input enabled, pulldown wird enabled, und aufwachen bei positiver Flanke PIN_Config PinTableWakeUp[] = { Board_PIR_Out_Lo | PIN_INPUT_EN | PIN_PULLDOWN | PINCC26XX_WAKEUP_POSEDGE, Board_PIR_Out_Hi | PIN_INPUT_EN | PIN_PULLDOWN | PINCC26XX_WAKEUP_POSEDGE, PIN_TERMINATE /* Terminate list */ }; /* Pin interrupt */ // Die genannten Pins werden Input enabled, kein Pull Up oder Down, und aufwachen bei positiver Flanke PIN_Config intrPinTable[] = { Board_PIR_Out_Lo | PIN_INPUT_EN | PIN_NOPULL | PIN_HYSTERESIS, Board_PIR_Out_Hi | PIN_INPUT_EN | PIN_NOPULL | PIN_HYSTERESIS, PIN_TERMINATE }; PIN_Handle intr_handle; // Pin_State benötigt ein "Handle" und dieses wird hier definiert PIN_State intr_state; /***** Function definitions *****/ void TxTask_init() // kann man wohl so lassen { Task_Params_init(&txTaskParams); // "Task_Params_init" Cluster wird befüllt txTaskParams.stackSize = TX_TASK_STACK_SIZE; // Stack Size txTaskParams.priority = TX_TASK_PRIORITY; // Task Priorität txTaskParams.stack = &txTaskStack; // Stack Bezeichnung txTaskParams.arg0 = (UInt)1000000; // Check ich nicht, steht aber überall Task_construct(&txTask, txTaskFunction, &txTaskParams, NULL); // Ein Objekt wird gebildet und nicht erstellt. Um es zu benutzen muss ein Handle erstellt werden. } static void txTaskFunction(UArg arg0, UArg arg1) { /* Init task TI-RTOS objects */ initializeTask(); // Der Task wird initialisiert /* Backdoor access */ uint8_t modeValue = PIN_getInputValue(Board_Mode); // Der Wert am Pin wird eingelesen, ist er 1 = high, so wird das Modul in den Shutdown Modus gefahren if(modeValue == 1) { Power_shutdown(NULL); // Energiesparmodus oder? //Trap code here while(1); } /* Get the reason for reset */ uint32_t rSrc = SysCtrlResetSourceGet(); // Der Grund für den Reset wird ermittelt if(rSrc == RSTSRC_WAKEUP_FROM_SHUTDOWN) // Falls Interrupt ausgelöst wurde wird diese Schleife ausgeführt { /*** Pin interrupt ***/ // Configure GPIO interrupt intr_handle = PIN_open(&intr_state, intrPinTable); // Nicht durch den "Test Debug" sondern durch den Interrupt definiert das Handle die Pins PIN_registerIntCb(intr_handle, &intr_HwiFxn); // Registriert eine Callback Funktion wenn ein HW-Interrupt aufgetreten ist PIN_setConfig(intr_handle, PIN_BM_IRQ, Board_PIR_Out_Lo | PIN_IRQ_POSEDGE); // IRQ bei positiver Flanke ausgelöst PIN_setConfig(intr_handle, PIN_BM_IRQ, Board_PIR_Out_Hi | PIN_IRQ_POSEDGE); // IRQ bei positiver Flanke ausgelöst //Send ON packet sendPacket(0xAA); move = move + 1; //Wait to make sure there are no more additional movements. //If any movement detected, counter is restarted in the ISR Clock_setTimeout(radioSyncTxClockHandle, PIR_QUIET_TIME / Clock_tickPeriod); // Warte bis counter abgelaufen und geht wieder auf inaktiv Clock_start(radioSyncTxClockHandle); Semaphore_pend(radioSyncTxSemHandle, BIOS_WAIT_FOREVER); // Task wird geblockt //Send OFF packet sendPacket(0xFF); //Wait for sensor to settle while(1) // Die Komparatorwerte werden getestet { uint8_t pirLowValue = PIN_getInputValue(Board_PIR_Out_Lo); // Checke Pin Wert vom einen Pin uint8_t pirHighValue = PIN_getInputValue(Board_PIR_Out_Hi); // Checke Pin Wert vom anderen Pin if(pirLowValue == 0 && pirHighValue == 0) // Sind beide Pins low, ist der Sensor "gesettelt" { sendPacket(0x55); break; } } } else // Falls der Reset anders ausgelöst wurde als durch Interrupt, also durch Einschalten { // Den Start sollte man so lassen! /*** Power on reset wakeup ***/ //Send initial packet to show system is up sendPacket(0x00); puts("System is up!\n"); move = 0; // reset move variable always at beginning while(1) { //Wait for sensor to start up and settle Clock_setTimeout(radioSyncTxClockHandle, PIR_SETTLE_TIME / Clock_tickPeriod); // Genauso wie im case zuvor Clock_start(radioSyncTxClockHandle); Semaphore_pend(radioSyncTxSemHandle, BIOS_WAIT_FOREVER); //Check value of comparators. If not low, wait for more time uint8_t pirLowValue = PIN_getInputValue(Board_PIR_Out_Lo); uint8_t pirHighValue = PIN_getInputValue(Board_PIR_Out_Hi); if(pirLowValue == 0 && pirHighValue == 0) // Wenn beide low sind, sende das "Testpacket" { break; } else // Wenn nicht beide Low sind, sende Error packet { //Send error packet sendPacket(0xEE); } } //Send packet to show system is up and running sendPacket(0x11); puts("System is running!"); } // Nach Interrupt oder Power up Routine geht es hier weiter! /* Wait for sensor to settle after RF transmission */ Task_sleep(PIR_SHUTDOWN_TIME / Clock_tickPeriod); // Der aktuelle Task wird geblockt /* Go to shutdown to wait for next PIR interrupt */ PINCC26XX_setWakeup(PinTableWakeUp); // Es werden die Pins nach dem "PinTableWakeUp" gesetzt und er geht in den Shutdown Modus Power_shutdown(NULL); /* Should never get here, since shutdown will reset */ while(1); } static void initializeTask(void) // sollte man so lassen können { /* Setup clock used for sync TX */ // Clock Parameter wurden gesetzt und Handles initialisiert Clock_Params radioSyncTxClockParams; Clock_Params_init(&radioSyncTxClockParams); radioSyncTxClockParams.startFlag = 0; radioSyncTxClockParams.period = 0; /* One-off clock */ Clock_construct(&radioSyncTxClock, radioSyncTxClockCallback, 0, &radioSyncTxClockParams); radioSyncTxClockHandle = Clock_handle(&radioSyncTxClock); /* Create semaphore to do sync TX */ // Semaphor und zugehöriges Handle wird initialisiert Semaphore_Params radioSyncTxParams; Semaphore_Params_init(&radioSyncTxParams); Semaphore_construct(&radioSyncTxSem, 0, &radioSyncTxParams); radioSyncTxSemHandle = Semaphore_handle(&radioSyncTxSem); } static void radioSyncTxClockCallback(UArg a0) // semaphore_post führt dazu, dass das SemaphoreHandle um 1 erhöht wird { Semaphore_post(radioSyncTxSemHandle); } void intr_HwiFxn(PIN_Handle hPin, PIN_Id pinId) // Wenn die pinId dem Hi und Lo Pin entspricht, wird die Clock gestoppt, ein TO gesetzt und wieder gestartet { if(pinId == Board_PIR_Out_Lo || pinId == Board_PIR_Out_Hi) // Sollte nach einer gemessenen Bewegung zutreffen { Clock_stop(radioSyncTxClockHandle); Clock_setTimeout(radioSyncTxClockHandle, PIR_QUIET_TIME / Clock_tickPeriod); // Warte bis Modul wieder inaktiv wird Clock_start(radioSyncTxClockHandle); } } static void sendPacket(uint8_t data) { uint32_t time; /* Init Radio parameters */ RF_Params_init(&rfParams); /* Construct payload */ packet[0] = 04; packet[1] = 89; packet[2] = data; /* Configure radio */ RF_cmdPropTx.pktLen = PAYLOAD_LENGTH; // Paketlänge in Bytes RF_cmdPropTx.pPkt = packet; // Paketarray, dass gesendet werden soll und max. der gesetzten Paketlänge entspricht RF_cmdPropTx.startTrigger.triggerType = TRIG_ABSTIME; // Muss man noch nachlesen was das soll RF_cmdPropTx.startTrigger.pastTrig = 1; // Muss man noch nachlesen was das soll /* Request access to the radio */ rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, &rfParams); /* Set the frequency */ RF_postCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL); /* Send packet */ // Nach jedem abgelaufenem Interval wird ein Paket gesendet time = RF_getCurrentTime(); time += PACKET_INTERVAL; RF_cmdPropTx.startTime = time; RF_Event result = RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropTx, RF_PriorityNormal); if (result != RF_EventCmdDone) { // Error while(1); } /* Close radio to save power */ RF_close(rfHandle); /* Power down the radio */ RF_yield(rfHandle); } /* * ======== main ======== */ int main(void) // Hier geschieht nur die Initialisierung, der eigentliche Code wird in der StartUp und Interrupt Routine abgerufen { /* Call board init functions. */ // Hier werden die Boardfunktionen initialisiert Board_initGeneral(); /* Initialize task */ // Hier wird der Task initialisiert TxTask_init(); /* Start BIOS */ // Hier wird das TI-RTOS gestartet BIOS_start(); return (0); }
Kind regards
Stefan