1 // ********************************************************************* 2 // Custom DPA Handler code - Handling buttons * 3 // ********************************************************************* 4 // Copyright (c) MICRORISC s.r.o. 5 // 6 // File: $RCSfile: CustomDpaHandler-Buttons.c,v $ 7 // Version: $Revision: 1.15 $ 8 // Date: $Date: 2022/02/25 09:41:25 $ 9 // 10 // Revision history: 11 // 2022/02/24 Release for DPA 4.17 12 // 2019/01/10 Release for DPA 4.00 13 // 14 // ********************************************************************* 15 16 // Online DPA documentation https://doc.iqrf.org/DpaTechGuide/ 17 18 // Default IQRF include (modify the path according to your setup) 19 #include "IQRF.h" 20 21 // Default DPA header (modify the path according to your setup) 22 #include "DPA.h" 23 // Default Custom DPA Handler header (modify the path according to your setup) 24 #include "DPAcustomHandler.h" 25 26 //############################################################################################ 27 28 // Button descriptor 29 typedef struct 30 { 31 // Timer to measure debouncing, recommended to be the 1st field to save the code 32 uns8 Timer; 33 // Last button state [must be initialized to 0xFF if the initial state of the button is not sure to be HIGH] 34 uns8 LastState; 35 // Button's PIC port: 0 = PORTA, 1 = PORTB, ... [must be initialized] 36 uns8 Port; 37 // Button's bit mask (only one bit must be set) [must be initialized] 38 uns8 ButtonMask; 39 // Debounce interval measured in the timer ticks + 1 [must be initialized] 40 uns8 DebounceDelay; 41 // 0 if button is HIGH, 1 if button is LOW 42 uns8 ButtonIsLow; 43 } TButton; 44 45 // Handles the button and sets ButtonIsLow appropriately 46 void HandleButton( uns16 pButton @ FSR0 ); 47 48 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location! 49 //############################################################################################ 50 bit CustomDpaHandler() 51 //############################################################################################ 52 { 53 // Handler presence mark 54 clrwdt(); 55 56 // We demonstrate 2 buttons by 1 physical button but with different debouncing value 57 static TButton ButtonFast, ButtonSlow; 58 59 // Detect DPA event to handle (unused event handlers can be commented out or even deleted) 60 switch ( GetDpaEvent() ) 61 { 62 // ------------------------------------------------- 63 case DpaEvent_Interrupt: 64 // Do an extra quick background interrupt work 65 // ! The time spent handling this event is critical.If there is no interrupt to handle return immediately otherwise keep the code as fast as possible. 66 // ! Make sure the event is the 1st case in the main switch statement at the handler routine.This ensures that the event is handled as the 1st one. 67 // ! It is desirable that this event is handled with immediate return even if it is not used by the custom handler because the Interrupt event is raised on every MCU interrupt and the “empty” return handler ensures the shortest possible interrupt routine response time. 68 // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy. 69 // ! Make sure race condition does not occur when accessing those variables at other places. 70 // ! Make sure( inspect.lst file generated by C compiler ) compiler does not create any hidden temporary local variable( occurs when using division, multiplication or bit shifts ) at the event handler code.The name of such variable is usually Cnumbercnt. 71 // ! Do not call any OS functions except setINDFx(). 72 // ! Do not use any OS variables especially for writing access. 73 // ! All above rules apply also to any other function being called from the event handler code, although calling any function from Interrupt event is not recommended because of additional MCU stack usage. 74 75 // If TMR6 interrupt occurred 76 if ( TMR6IF ) 77 { 78 // Unmask interrupt 79 TMR6IF = FALSE; 80 81 // Handle buttons 82 HandleButton( &ButtonFast ); 83 HandleButton( &ButtonSlow ); 84 85 // Demonstration of the fast button 86 if ( ButtonFast.ButtonIsLow.0 ) 87 setLEDR(); 88 else 89 stopLEDR(); 90 91 // Demonstration of the slow button 92 if ( ButtonSlow.ButtonIsLow.0 ) 93 setLEDG(); 94 else 95 stopLEDG(); 96 } 97 98 return Carry; 99 100 // ------------------------------------------------- 101 case DpaEvent_Init: 102 // Do a one time initialization before main loop starts 103 104 // Initialize buttons' descriptors (CC5X does not support initialization of the static variables) 105 106 // Fast button @ IQRF standard button 107 ButtonFast.LastState = 0xFF; 108 ButtonFast.Port = 1; // PORTB 109 ButtonFast.ButtonMask = 0b0001.0000; // PORTB.4 110 ButtonFast.DebounceDelay = 2 + 1 /* x64ms */; 111 112 // Slow button @ IQRF standard button 113 ButtonSlow.LastState = 0xFF; 114 ButtonSlow.Port = 1; // PORTB 115 ButtonSlow.ButtonMask = 0b0001.0000; // PORTB.4 116 ButtonSlow.DebounceDelay = 15 + 1 /* x64ms */; 117 118 // Setup TMR6 for 64 ms interval 119 _PR6 = 250 - 1; 120 #if defined( TR7xG ) 121 TMR6MD = 0; 122 T6CON = 0b1.110.1111; 123 // Timer2/4/6 Clock Select bits = FOSC/4 124 T6CLKCON |= 0b0000.0001; 125 #else 126 T6CON = 0b0.1111.1.11; 127 #endif 128 TMR6IE = TRUE; 129 break; 130 131 // ------------------------------------------------- 132 case DpaEvent_AfterSleep: 133 // Called on wake-up from sleep 134 TMR6IE = TRUE; 135 _TMR6ON = TRUE; 136 break; 137 138 // ------------------------------------------------- 139 case DpaEvent_BeforeSleep: 140 // Called before going to sleep (the same handling as DpaEvent_DisableInterrupts event) 141 // ------------------------------------------------- 142 case DpaEvent_DisableInterrupts: 143 // Called when device needs all hardware interrupts to be disabled (before Reset, Restart, LoadCode, Remove bond, and Run RFPGM) 144 // Must not use TMR6 any more 145 _TMR6ON = FALSE; 146 TMR6IE = FALSE; 147 break; 148 } 149 150 return FALSE; 151 } 152 153 //############################################################################################ 154 void HandleButton( uns16 pButton @ FSR0 ) 155 //############################################################################################ 156 { 157 // FSR0 points to the button's descriptor 158 // (Local variables must be static as they are used inside interrupt routine) 159 160 // Timer is active (non zero)? 161 W = FSR0[offsetof( TButton, Timer )]; 162 if ( W != 0 ) // Note: must not modify W 163 { 164 // Yes, decrement the timer 165 FSR0 += offsetof( TButton, Timer ); // Note: Timer is the 1st field of TButton so this generates no code and must not modify W 166 setINDF0( W - 1 ); 167 FSR0 += -(int8)offsetof( TButton, Timer ); // Note: Timer is the 1st field of TButton so this generates no code, casting fixes CC5X bug 168 } 169 170 // FSR1 will point to the button's port 171 FSR1L = FSR0[offsetof( TButton, Port )] + ( &PORTA & 0xFF ); 172 FSR1H = &PORTA >> 8; 173 174 // Current state of the button, only the button bit is used, other bits are masked to zero 175 static uns8 state; 176 state = *FSR1 & FSR0[offsetof( TButton, ButtonMask )]; 177 178 // Button state changed? 179 if ( ( state ^ FSR0[offsetof( TButton, LastState )] ) != 0 ) 180 { 181 FSR0 += offsetof( TButton, Timer ); // Note: Timer is the 1st field of TButton so this generates no code and must not modify W 182 // Initialize timer for debouncing 183 setINDF0( FSR0[offsetof( TButton, DebounceDelay ) - offsetof( TButton, Timer )] ); 184 // Adjust pointer to LastState field 185 FSR0 += (int8)( offsetof( TButton, LastState ) - offsetof( TButton, Timer ) ); // Note: casting fixes CC5X bug 186 // Store the current state as the last one 187 setINDF0( state ); 188 return; // Note: saves Flash by direct GOTO setINDF0 189 } 190 191 // Timer is almost over? 192 if ( FSR0[offsetof( TButton, Timer )] != 1 ) 193 // No 194 return; 195 196 // The button state was stable for the debounce interval, prepare the pointer to store the new state 197 FSR0 += offsetof( TButton, ButtonIsLow ); 198 // Ready for new state "button is HIGH" 199 W = FALSE; 200 // Is button LOW? 201 if ( state == 0 ) // Note: must not modify W 202 // Ready for new state "button is LOW" 203 W = TRUE; 204 205 // Set the button external state 206 setINDF0( W ); 207 } 208 209 //############################################################################################ 210 // Default Custom DPA Handler header; 2nd include implementing a Code bumper to detect too long code of the Custom DPA Handler (modify the path according to your setup) 211 #include "DPAcustomHandler.h" 212 //############################################################################################ 213