1 // ************************************************************************** 2 // Custom DPA Handler code example - User peripheral implementation - PWM * 3 // ************************************************************************** 4 // Copyright (c) IQRF Tech s.r.o. 5 // 6 // File: $RCSfile: CustomDpaHandler-UserPeripheral-PWMandTimer.c,v $ 7 // Version: $Revision: 1.9 $ 8 // Date: $Date: 2017/08/31 08:32:32 $ 9 // 10 // Revision history: 11 // 2017/03/13 Release for DPA 3.00 12 // 2015/09/03 Release for DPA 2.21 13 // 14 // ********************************************************************* 15 16 // Online DPA documentation http://www.iqrf.org/DpaTechGuide/ 17 18 // This example demonstrates usage of PWM and Timer at same time 19 // It implements one user peripheral PNUM=0x20, PCMD=0x00 20 // Data contains list of commands at the following format 21 // 0x00, PWM 22 // Sets 8bit PWM duty cycle to value "PWM" 23 // 0x01, loopLow8, loopHigh8, pwmAddlow8, pwmAddhigh8 24 // Adds 16bit "pwmAdd" value divided by 256 "loop" times. Time unit is approx 16 ms 25 // 0x02 26 // Starts executing command from the beginning 27 // 0x03 28 // Stops execution of commands 29 30 // This example works only at STD mode, not at LP mode 31 32 // Example data for PNUM=0x20, PCMD=0x00 33 // 0x00, 0x00, 34 // - Sets PWM duty cycle to 0 35 // 0x01, 0x00, 0x01, 0x40, 0x00, 36 // - Adds 0x0100 = 256 times every 16 ms value 0x0040 / 256 = 0.25 to the duty cycle 37 // 0x01, 0x00, 0x01, 0xC0, 0xFF, 38 // - Adds 0x0100 = 256 times every 16 ms value 0xFFC0 / 256 = -0x0040 / 256 = -0.25 to the duty cycle 39 // 0x01, 0x80, 0x00, 0x00, 0x00, 40 // - Adds 0x0800 = 128 times every 16 ms value 0 to the duty cycle (wait delay for approx 2 s) 41 // 0x02 42 // - Starts again 43 44 // The example will not work at demo DPA version because demo DPA does not support the following Custom DPA Handler events: DpaEvent_Interrupt, DpaEvent_BeforeSleep, DpaEvent_AfterSleep, DpaEvent_Reset, DpaEvent_DisableInterrupts, DpaEvent_ReceiveDpaResponse, DpaEvent_IFaceReceive, DpaEvent_ReceiveDpaRequest, DpaEvent_BeforeSendingDpaResponse 45 46 // Default IQRF include (modify the path according to your setup) 47 #include "IQRF.h" 48 49 // Default DPA header (modify the path according to your setup) 50 #include "DPA.h" 51 // Default Custom DPA Handler header (modify the path according to your setup) 52 #include "DPAcustomHandler.h" 53 54 // PWM commands 55 typedef enum 56 { 57 CMD_SET_PWM = 0, 58 CMD_CHANGE_PWM = 1, 59 CMD_LOOP = 2, 60 CMD_STOP = 3 61 }; 62 63 //############################################################################################ 64 65 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location! 66 //############################################################################################ 67 bit CustomDpaHandler() 68 //############################################################################################ 69 { 70 // Handler presence mark 71 clrwdt(); 72 73 // List of commands 74 static uns8 Cmds[40]; 75 // Index of the next command 76 static uns8 CmdsIndex; 77 // Loop for changing PWM 78 static uns16 ChangePWMloop; 79 // Value to add to PWM during change 80 static uns16 ChangePWMadd; 81 // Full 16b PWM duty cycle value, only higher part is used at MCU 82 static uns16 CCPR3Lshadow; 83 84 // Detect DPA event to handle 85 switch ( GetDpaEvent() ) 86 { 87 // ------------------------------------------------- 88 case DpaEvent_Interrupt: 89 // Do an extra quick background interrupt work 90 // ! 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. 91 // ! 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. 92 // ! 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. 93 // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy. 94 // ! Make sure race condition does not occur when accessing those variables at other places. 95 // ! 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. 96 // ! Do not call any OS functions except setINDFx(). 97 // ! Do not use any OS variables especially for writing access. 98 // ! 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. 99 100 // If TMR6 interrupt occurred 101 if ( TMR6IF ) 102 { 103 // Unmask interrupt 104 TMR6IF = 0; 105 106 // Changing PWM? 107 if ( ChangePWMloop != 0 ) 108 { 109 // Decrease loop 110 ChangePWMloop--; 111 // Add PWM 112 CCPR3Lshadow += ChangePWMadd; 113 // Copy to MCU 114 CCPR3L = CCPR3Lshadow.high8; 115 } 116 else 117 { 118 // Get command pointer 119 FSR0 = Cmds + CmdsIndex; 120 switch ( FSR0[0] ) 121 { 122 // Set PWM 123 case CMD_SET_PWM: 124 // Next cmd 125 CmdsIndex += 1 + 1; 126 // Get value 127 CCPR3Lshadow.high8 = CCPR3L = FSR0[1]; 128 CCPR3Lshadow.low8 = 0; 129 break; 130 131 // Change PWM 132 case CMD_CHANGE_PWM: 133 // Next cmd 134 CmdsIndex += 1 + 4; 135 // Get loop count 136 ChangePWMloop.low8 = FSR0[1]; 137 ChangePWMloop.high8 = FSR0[2]; 138 // Get added value 139 ChangePWMadd.low8 = FSR0[3]; 140 ChangePWMadd.high8 = FSR0[4]; 141 break; 142 143 // Loop commands 144 case CMD_LOOP: 145 // Start from the 1st command 146 CmdsIndex = 0; 147 break; 148 149 // Stop commands 150 case CMD_STOP: 151 default: 152 break; 153 } 154 } 155 } 156 return Carry; 157 158 // ------------------------------------------------- 159 case DpaEvent_Init: 160 // Do a one time initialization work before main loop starts 161 162 // Start with no commands 163 Cmds[0] = CMD_STOP; 164 // CmdsIndex = 0 // By C definition 165 166 // Definitions used for TR72 having connected pins 167 #define _OUT_A5 TRISA.5 168 #define _OUT_B4 TRISB.4 169 #define _OUT_C6 TRISC.6 170 #define _PIN_C6 LATC.6 171 172 // Read module info into bufferINFO 173 moduleInfo(); 174 // TR module with connected pins? 175 if ( bufferINFO[5].7 == 0 ) 176 { 177 _OUT_A5 = 1; 178 _OUT_B4 = 1; 179 } 180 181 // Single output; PxA modulated; PxB, PxC, PxD assigned as port pins 182 // PWM mode: PxA, PxC active-high; PxB, PxD active-high 183 CCP3CON = 0b00.00.1100; 184 // PWM duty cycle 185 CCPR3L = 0; 186 // Period 187 PR6 = 0xff; 188 // CCP3 is based off Timer6 in PWM mode 189 CCPTMRS0 = 0b00100000; 190 // CCP3/P3A function is CCP3 191 CCP3SEL = 0; 192 #if F_OSC == 8000000 193 // Prescaler 16, Postscaler 8, 16 * 8 * 256 = 32768 = 61 Hz = 16 ms @8MHz 194 // TMR6 on 195 T6CON = 0b0.0111.1.10; 196 #elif F_OSC == 16000000 197 // Prescaler 16, Postscaler 8, 16 * 16 * 256 = 65536 = 61 Hz = 16 ms @16MHz 198 // TMR6 on 199 T6CON = 0b0.1111.1.10; 200 #else 201 #error Unsupported oscillator frequency 202 #endif 203 204 // TMR6 interrupt 205 TMR6IE = 1; 206 // Set output 207 _OUT_C6 = 0; 208 209 break; 210 211 // ------------------------------------------------- 212 case DpaEvent_AfterSleep: 213 // Called on wake-up from sleep 214 TMR6IE = TRUE; 215 TMR6ON = TRUE; 216 break; 217 218 // ------------------------------------------------- 219 case DpaEvent_BeforeSleep: 220 // Called before going to sleep (the same handling as DpaEvent_DisableInterrupts event) 221 222 // ------------------------------------------------- 223 case DpaEvent_DisableInterrupts: 224 // Called when device needs all hardware interrupts to be disabled (before Reset, Restart and RFPGM) 225 // Must not use TMR6 any more 226 TMR6ON = FALSE; 227 TMR6IE = FALSE; 228 _PIN_C6 = FALSE; 229 break; 230 231 // ------------------------------------------------- 232 case DpaEvent_DpaRequest: 233 // Called to interpret DPA request for peripherals 234 // ------------------------------------------------- 235 // Peripheral enumeration 236 if ( IsDpaEnumPeripheralsRequest() ) 237 { 238 // We implement 1 user peripheral 239 _DpaMessage.EnumPeripheralsAnswer.UserPerNr = 1; 240 FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_USER + 0 ); 241 _DpaMessage.EnumPeripheralsAnswer.HWPID = 0x000F; 242 _DpaMessage.EnumPeripheralsAnswer.HWPIDver = 0xFeFe; 243 244 DpaHandleReturnTRUE: 245 return TRUE; 246 } 247 // ------------------------------------------------- 248 // Get information about peripheral 249 else if ( IsDpaPeripheralInfoRequest() ) 250 { 251 if ( _PNUM == PNUM_USER + 0 ) 252 { 253 _DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_USER_AREA; 254 _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_WRITE; 255 goto DpaHandleReturnTRUE; 256 } 257 258 break; 259 } 260 // ------------------------------------------------- 261 else 262 { 263 // Handle peripheral command 264 if ( _PNUM == PNUM_USER + 0 ) 265 { 266 // Check command 267 if ( _PCMD != 0 ) 268 DpaApiReturnPeripheralError( ERROR_PCMD ); 269 270 // Check data length 271 if ( _DpaDataLength > ( sizeof( Cmds ) - 1 ) ) 272 DpaApiReturnPeripheralError( ERROR_DATA_LEN ); 273 274 // Copy commands and always append CMD_STOP for sure 275 GIE = FALSE; 276 copyMemoryBlock( _DpaMessage.Request.PData, Cmds, sizeof( Cmds ) - 1 ); 277 writeToRAM( Cmds + _DpaDataLength, CMD_STOP ); 278 // Start new commands 279 CmdsIndex = 0; 280 ChangePWMloop = 0; 281 GIE = TRUE; 282 283 // Write no error 284 _DpaDataLength = 0; 285 goto DpaHandleReturnTRUE; 286 } 287 } 288 } 289 290 return FALSE; 291 } 292 293 //############################################################################################ 294 // Default Custom DPA Handler header; 2nd include to implement Code bumper to detect too long code of the Custom DPA Handler (modify the path according to your setup) 295 #include "DPAcustomHandler.h" 296 //############################################################################################