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