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-PWM.c,v $ 7 // Version: $Revision: 1.27 $ 8 // Date: $Date: 2017/08/09 12:24:47 $ 9 // 10 // Revision history: 11 // 2017/03/13 Release for DPA 3.00 12 // 2016/09/12 Release for DPA 2.28 13 // 2015/08/05 Release for DPA 2.20 14 // 2014/10/31 Release for DPA 2.10 15 // 2014/04/30 Release for DPA 2.00 16 // 17 // ********************************************************************* 18 19 // Online DPA documentation http://www.iqrf.org/DpaTechGuide/ 20 21 // This example implements the user peripheral PWM having the standard PWM peripheral from demo DPA behavior 22 // This example works only at STD mode, not at LP mode 23 24 // Default IQRF include (modify the path according to your setup) 25 #include "IQRF.h" 26 27 // Default DPA header (modify the path according to your setup) 28 #include "DPA.h" 29 // Default Custom DPA Handler header (modify the path according to your setup) 30 #include "DPAcustomHandler.h" 31 32 //############################################################################################ 33 34 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location! 35 //############################################################################################ 36 bit CustomDpaHandler() 37 //############################################################################################ 38 { 39 // Handler presence mark 40 clrwdt(); 41 42 // Detect DPA event to handle 43 switch ( GetDpaEvent() ) 44 { 45 // ------------------------------------------------- 46 case DpaEvent_Interrupt: 47 // Do an extra quick background interrupt work 48 // ! 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. 49 // ! 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. 50 // ! 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. 51 // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy. 52 // ! Make sure race condition does not occur when accessing those variables at other places. 53 // ! 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. 54 // ! Do not call any OS functions except setINDFx(). 55 // ! Do not use any OS variables especially for writing access. 56 // ! 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. 57 58 DpaHandleReturnTRUE: 59 return TRUE; 60 61 // ------------------------------------------------- 62 case DpaEvent_DpaRequest: 63 // Called to interpret DPA request for peripherals 64 // ------------------------------------------------- 65 // Peripheral enumeration 66 if ( IsDpaEnumPeripheralsRequest() ) 67 { 68 // We implement 1 user peripheral 69 _DpaMessage.EnumPeripheralsAnswer.UserPerNr = 1; 70 FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_USER + 0 ); 71 _DpaMessage.EnumPeripheralsAnswer.HWPID = 0x000F; 72 _DpaMessage.EnumPeripheralsAnswer.HWPIDver = 0xabcd; 73 74 goto DpaHandleReturnTRUE; 75 } 76 // ------------------------------------------------- 77 // Get information about peripheral 78 else if ( IsDpaPeripheralInfoRequest() ) 79 { 80 if ( _PNUM == PNUM_USER + 0 ) 81 { 82 _DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_PWM; 83 _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_WRITE; 84 goto DpaHandleReturnTRUE; 85 } 86 87 break; 88 } 89 // ------------------------------------------------- 90 else 91 { 92 // Handle peripheral command 93 if ( _PNUM == PNUM_USER + 0 ) 94 { 95 // Check command 96 if ( _PCMD != 0 ) 97 DpaApiReturnPeripheralError( ERROR_PCMD ); 98 99 // Check data length 100 if ( _DpaDataLength != sizeof( _DpaMessage.PerPwmSet_Request ) ) 101 DpaApiReturnPeripheralError( ERROR_DATA_LEN ); 102 103 // Read module info into bufferINFO 104 moduleInfo(); 105 106 // We use FSR0 to access PerPwmSet structure and to avoid to many MOVLB MCU instructions 107 FSR0 = (uns16)&_DpaMessage.PerPwmSet_Request; 108 109 #define _Prescaler FSR0[offsetof(TPerPwmSet_Request,Prescaler)] 110 #define _Period FSR0[offsetof(TPerPwmSet_Request,Period)] 111 #define _Duty FSR0[offsetof(TPerPwmSet_Request,Duty)] 112 113 // prescaler has to be in range 0 - 3 114 // 2 LSbs of duty cycle is coded into 4 and 5 bit of prescaler 0b00xx0000 115 if ( ( 0x03 < _Prescaler ) && ( 0x03 < ( _Prescaler >> 4 ) ) ) 116 DpaApiReturnPeripheralError( ERROR_DATA ); 117 118 // Definitions used for TR72 having connected pins 119 #define _OUT_A5 TRISA.5 120 #define _OUT_B4 TRISB.4 121 #define _OUT_C6 TRISC.6 122 #define _PIN_C6 LATC.6 123 124 // PWM setup 125 if ( 0x00 == _Prescaler && 0x00 == _Period && 0x00 == _Duty ) 126 { 127 // Stop PWM 128 _PIN_C6 = 0; 129 130 T6CON = 0; 131 CCPTMRS0 = 0; 132 CCP3CON = 0; 133 } 134 else 135 { // Start PWM 136 // TR module with connected pins? 137 if ( bufferINFO[5].7 == 0 ) 138 { 139 _OUT_A5 = 1; 140 _OUT_B4 = 1; 141 } 142 143 // PWM duty cycle 144 CCPR3L = _Duty; 145 // Change duty cycle only 146 CCP3CON = 0b00001100 | ( _Prescaler & 0b00110000 ); 147 148 if ( _Period != PR6 || ( ( _Prescaler ^ T6CON ) & 0b00000011 ) != 0 ) 149 { 150 // Prescaler 151 T6CON = _Prescaler & 0b00000011; 152 153 // Set timer6 as CCP3 timer 154 CCPTMRS0 = 0b00100000; 155 // CCP3 single mode coded from prescaler byte 156 // Select RC6 as P3A function output 157 CCP3SEL = 0; 158 159 PR6 = _Period; // PWM period 160 161 TMR6IF = 0; 162 TMR6ON = 1; 163 // To send a complete duty cycle and period on the first PWM 164 while ( !TMR6IF ); 165 } 166 167 _OUT_C6 = 0; 168 } 169 170 WriteNoError: 171 _DpaDataLength = 0; 172 goto DpaHandleReturnTRUE; 173 } 174 } 175 } 176 177 return FALSE; 178 } 179 180 //############################################################################################ 181 // 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) 182 #include "DPAcustomHandler.h" 183 //############################################################################################