1 // ********************************************************************* 2 // Custom DPA Handler code template * 3 // ********************************************************************* 4 // Copyright (c) MICRORISC s.r.o. 5 // 6 // File: $RCSfile: CustomDpaHandler-SerialSpiRam.c,v $ 7 // Version: $Revision: 1.1 $ 8 // Date: $Date: 2026/05/28 11:31:00 $ 9 // 10 // Revision history: 11 // 2026/05/27 Release for DPA 4.33 12 // 13 // ********************************************************************* 14 15 // Online DPA documentation https://doc.iqrf.org/DpaTechGuide/ 16 17 // This example uses the serial SPI RAM 23LCV512. 18 // The RAM can be written to and read from using the same commands as the embedded EEPROM peripheral, with a user peripheral PNUM=0x20 (https://doc.iqrf.org/DpaTechGuide/pages/eeeprom.html). 19 // 20 // The SDI and SDO signals are connected to save used GPIOs when the SDO_SDI symbol is defined. 21 // To minimize short-circuit current spikes, a 100R-1k resistor must then be placed between the connected SDI and SDO at the RAM and the PIC GPIO. 22 23 // Default IQRF include (modify the path according to your setup) 24 #include "IQRF.h" 25 26 // Default DPA header (modify the path according to your setup) 27 #include "DPA.h" 28 // Default Custom DPA Handler header (modify the path according to your setup) 29 #include "DPAcustomHandler.h" 30 31 // Define to use connected SDO and SDI, they share the same signal 32 // #define SDO_SDI 33 34 // SPI signals to PIN assignment: 35 // TR module pin DK-EVAL-04x pin SPI 36 // --------------------------------------- 37 // C8 (RC5) 1 SDO, unused when SDO_SDI 38 // C7 (RC4) 2 SDI, also SDO when SDO_SDI 39 // C6 (RC3) 3 SCK 40 // C5 (RA5) 4 CS 41 42 // _SS_ pin assignment (C5 = PORTA.5) 43 #define CS_PIN LATA.5 44 45 // Serial RAM commands 46 #define RAM_READ 0b0000.0011 47 #define RAM_WRITE 0b0000.0010 48 49 // Writes to and reads from RAM 50 void Ram( uns16 address, uns16 buffer, uns8 length, uns8 command ); 51 52 //############################################################################################ 53 // https://doc.iqrf.org/DpaTechGuide/pages/custom-dpa-handler.html 54 bit CustomDpaHandler() 55 //############################################################################################ 56 { 57 // Handler presence mark 58 clrwdt(); 59 60 // Detect DPA event to handle (unused event handlers can be commented out or even deleted) 61 switch ( GetDpaEvent() ) 62 { 63 // ------------------------------------------------- 64 case DpaEvent_Interrupt: 65 // Do an extra quick background interrupt work 66 // ! 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. 67 // ! 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. 68 // ! 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. 69 // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy. 70 // ! Make sure race condition does not occur when accessing those variables at other places. 71 // ! 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. 72 // ! Do not call any OS functions except setINDFx(). 73 // ! Do not use any OS variables especially for writing access. 74 // ! 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. 75 // https://doc.iqrf.org/DpaTechGuide/pages/EventInterrupt.html 76 return Carry; 77 78 // ------------------------------------------------- 79 case DpaEvent_Init: 80 // Do a one time initialization before main loop starts 81 // https://doc.iqrf.org/DpaTechGuide/pages/init.html 82 83 // Do a one time initialization before main loop starts 84 { 85 { // Initialize GPIOs to inputs and outputs 86 87 // Set idle level of SS 88 CS_PIN = 1; 89 90 #ifndef SDO_SDI 91 TRISC.5 = 0; // RC5 is output SDO (C8) 92 TRISC.4 = 1; // RC4 is input SDI (C7) 93 #else 94 TRISC.4 = 0; // RC4 is output SDO (C7) 95 #endif 96 97 TRISC.3 = 0; // RC3 is output SCK (C6) 98 TRISA.5 = 0; // RA5 is output SS (C5) 99 100 // TR module with connected pins? 101 moduleInfo(); 102 if ( ModuleInfo.TrType.7 == 0 ) 103 { 104 TRISC.6 = 1; // RC6 is input (connected to RA5 in parallel) 105 TRISB.4 = 1; // RB4 is input (connected to RA5 in parallel) 106 TRISC.7 = 1; // RC7 is input (connected to RC5 in parallel) 107 } 108 } 109 110 // Enable SPI module 111 MSSP1MD = 0; 112 113 { // PPS 114 unlockPPS(); 115 #ifndef SDO_SDI 116 SSP1DATPPS = 0x14; // RC4 is SDI 117 RC5PPS = 0x15; // RC5 is SDO 118 #else 119 SSP1DATPPS = 0x14; // RC4 is SDI 120 RC4PPS = 0x15; // RC4 is SDO 121 #endif 122 123 RC3PPS = 0x14; // RC3 is SCK 124 lockPPS(); 125 } 126 127 { // Setup SPI module 128 // SSPSTAT 129 // Transmit occurs on SCK rising edge 130 _CKE = 1; 131 // SSPCON1 132 // SPI enabled 133 // Idle state for clock is a low level 134 // CLK = 4 MHz @ 16 MHz 135 _SSPCON1 = 0b0.0.1.0.0000; 136 } 137 138 break; 139 } 140 141 // ------------------------------------------------- 142 case DpaEvent_DpaRequest: 143 // Called to interpret DPA request for peripherals 144 // https://doc.iqrf.org/DpaTechGuide/pages/EventDpaRequest.html 145 IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequest() 146 { 147 // ------------------------------------------------- 148 // Peripheral enumeration 149 // https://doc.iqrf.org/DpaTechGuide/pages/enumerate-peripherals.html 150 151 _DpaMessage.EnumPeripheralsAnswer.UserPerNr |= 1; 152 FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_USER ); 153 _DpaMessage.EnumPeripheralsAnswer.HWPID = 0x581F; 154 155 156 DpaHandleReturnTRUE: 157 return TRUE; 158 } 159 else 160 { 161 // ------------------------------------------------- 162 // Get information about peripheral 163 // https://doc.iqrf.org/DpaTechGuide/pages/get-peripheral-info.html 164 165 if ( _PNUM == PNUM_USER ) 166 { 167 _DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_BLOCK_EEPROM; 168 _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ_WRITE; 169 _DpaMessage.PeripheralInfoAnswer.Par1 = ( 0x10000 / 256 ) & 0xFF; 170 goto DpaHandleReturnTRUE; 171 } 172 173 break; 174 } 175 176 // ------------------------------------------------- 177 // Handle peripheral command 178 // https://doc.iqrf.org/DpaTechGuide/pages/handle-peripheral-request.html 179 180 if ( _PNUM == PNUM_USER ) 181 { 182 switch ( _PCMD ) 183 { 184 case CMD_EEEPROM_XREAD: 185 if ( _DpaMessage.XMemoryRequest.ReadWrite.Read.Length > sizeof( _DpaMessage.Response.PData ) ) 186 DpaApiReturnPeripheralError( ERROR_DATA ); 187 188 Ram( _DpaMessage.XMemoryRequest.Address, FSR0 /* same as _DpaMessage.Response.PData */, _DpaDataLength = _DpaMessage.XMemoryRequest.ReadWrite.Read.Length, RAM_READ ); 189 goto DpaHandleReturnTRUE; 190 191 case CMD_EEEPROM_XWRITE: 192 Ram( _DpaMessage.XMemoryRequest.Address, _DpaMessage.XMemoryRequest.ReadWrite.Write.PData, _DpaDataLength - XMEMORY_WRITE_REQUEST_OVERHEAD, RAM_WRITE ); 193 _DpaDataLength = 0; 194 goto DpaHandleReturnTRUE; 195 196 default: 197 DpaApiReturnPeripheralError( ERROR_PCMD ); 198 } 199 } 200 201 break; 202 } 203 204 DpaHandleReturnFALSE: 205 return FALSE; 206 } 207 208 //############################################################################################ 209 uns8 SPIwriteRead( uns8 data @ W ) 210 //############################################################################################ 211 { 212 // Reset interrupt flag 213 _SSPIF = 0; // Note: must not modify W 214 // Write the byte 215 _SSPBUF = W; 216 // Wait until the byte is transmitted/received 217 while ( !_SSPIF ); 218 // Return result 219 return _SSPBUF; 220 } 221 222 //############################################################################################ 223 void Ram( uns16 address @ param3, uns16 buffer @ FSR0, uns8 length @ param2, uns8 command ) 224 //############################################################################################ 225 { 226 // SPI SS - activate 227 CS_PIN = 0; 228 229 #ifdef SDO_SDI 230 // Get ready for the later PPS 231 unlockPPS(); 232 GIE = 1; 233 #endif 234 235 // Increase length for the upcoming optimized loop 236 length++; 237 238 SPIwriteRead( command ); 239 SPIwriteRead( address.high8 ); 240 SPIwriteRead( address.low8 ); 241 242 #ifdef SDO_SDI 243 // Switch from SDO to SDI in case of RAM_READ? 244 if ( ( command & ( RAM_READ ^ RAM_WRITE ) ) == ( RAM_READ & ~RAM_WRITE ) ) // Note: The expression is optimized by the compiler for the bit test because RAM_READ and RAM_WRITE differ by only one bit. 245 { 246 TRISC.4 = 1; // RC4 is input ready for SDI 247 RC4PPS = 0x00; // RC4 is not SDO any more 248 } 249 #endif 250 251 goto _inLoop; 252 do 253 { 254 setINDF0( SPIwriteRead( *FSR0 ) ); 255 FSR0++; 256 _inLoop: 257 } while ( --length ); 258 259 // SPI SS - deactivate 260 CS_PIN = 1; 261 262 #ifdef SDO_SDI 263 // Switch back from SDI to SDO in case of RAM_READ? 264 if ( ( command & ( RAM_READ ^ RAM_WRITE ) ) == ( RAM_READ & ~RAM_WRITE ) ) // Note: The expression is optimized by the compiler for the bit test because RAM_READ and RAM_WRITE differ by only one bit. 265 { 266 RC4PPS = 0x15; // RC4 is SDO again 267 TRISC.4 = 0; // RC4 is output ready for SDO again 268 } 269 270 GIE = 0; 271 lockPPS(); 272 #endif 273 } 274 275 //############################################################################################ 276 // 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) 277 #include "DPAcustomHandler.h" 278 //############################################################################################