1 // ************************************************************************** 2 // Custom DPA Handler code example - User peripheral supporting UART HW * 3 // ************************************************************************** 4 // Copyright (c) MICRORISC s.r.o. 5 // 6 // File: $RCSfile: CustomDpaHandler-UserPeripheral-HW-UART.c,v $ 7 // Version: $Revision: 1.30 $ 8 // Date: $Date: 2023/03/07 08:03:13 $ 9 // 10 // Revision history: 11 // 2023/03/07 Release for DPA 4.30 12 // 2022/10/05 Release for DPA 4.18 13 // 2022/02/24 Release for DPA 4.17 14 // 2017/08/14 Release for DPA 3.01 15 // 16 // ********************************************************************* 17 18 // Online DPA documentation https://doc.iqrf.org/DpaTechGuide/ 19 20 // This example implements the user peripheral supporting HW UART of the PIC 21 // This example works only at STD mode, not at LP mode 22 // RX = RC7 23 // TX = RC6 24 25 // Default IQRF include (modify the path according to your setup) 26 #include "IQRF.h" 27 28 // Default DPA header (modify the path according to your setup) 29 #include "DPA.h" 30 // Default Custom DPA Handler header (modify the path according to your setup) 31 #include "DPAcustomHandler.h" 32 33 //############################################################################################ 34 35 // TX byte to UART 36 void TxUART( uns8 data ); 37 // RX byte from UART; W = read byte, Carry = byte was read 38 bit RxUART(); 39 40 //############################################################################################ 41 42 // UART baud rate 43 #define UART_BAUD 19200 44 45 // Number of UART received bytes 46 uns8 RxDataLengthUART; 47 48 // Length of RX and TX buffers, must be power of 2 49 #define UART_BUFFER_LENGTH 16 50 51 #if 0 != ( UART_BUFFER_LENGTH & ( UART_BUFFER_LENGTH - 1 ) ) 52 #error UART_BUFFER_LENGTH is not power of 2 53 #endif 54 55 // Rx 56 // Circular RX UART buffer pointers 57 uns8 RxBufferPointerStartUART; 58 uns8 RxBufferPointerEndUART; 59 uns8 RxBufferUART[UART_BUFFER_LENGTH] /*@ PeripheralRam[0]*/; 60 61 // TX 62 // Circular TX UART buffer pointers 63 uns8 TxBufferPointerStartUART; 64 uns8 TxBufferPointerEndUART; 65 uns8 TxBufferUART[UART_BUFFER_LENGTH] /*@ PeripheralRam[UART_BUFFER_LENGTH]*/; 66 67 // Division macro with rounding 68 #define DIV(Dividend,Divisor) (((Dividend+((Divisor)>>1))/(Divisor))) 69 // PIC baud register computation 70 #define UART_SPBRG_VALUE( Baud ) ( DIV( F_OSC, ( ( ( uns24 )4 ) * ( Baud ) ) ) - 1 ) 71 72 73 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location! 74 //############################################################################################ 75 bit CustomDpaHandler() 76 //############################################################################################ 77 { 78 // Handler presence mark 79 clrwdt(); 80 81 // TXIE state before sleep 82 static bit wasTXIE; 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 // ----------------------------------------------------------------------------------------- 101 // UART Receive 102 // 103 if ( RCIF ) 104 { 105 // We ignore FERR 106 FSR1L = _RCREG; 107 // Put the received byte in circular buffer 108 if ( RxDataLengthUART < UART_BUFFER_LENGTH ) 109 { 110 // One more byte received 111 RxDataLengthUART++; 112 // Prepare pointer 113 FSR0 = RxBufferUART + RxBufferPointerEndUART; 114 // Recalculate tail pointer 115 // Optimization: Same as (UART_BUFFER_LENGTH is power of 2) : RxBufferPointerEndUART = ( RxBufferPointerEndUART + 1 ) % UART_BUFFER_LENGTH; 116 RxBufferPointerEndUART++; 117 RxBufferPointerEndUART &= ~UART_BUFFER_LENGTH; 118 // Store byte 119 setINDF0( FSR1L ); 120 } 121 } 122 123 // Overrun recovery (we do it after receiving UART byte in order to receive it as soon as possible) 124 if ( OERR ) 125 CREN = 0; 126 127 // Seems excess, but at the end it is shorted and faster than having this statement at else branch 128 CREN = 1; 129 130 // ----------------------------------------------------------------------------------------- 131 // UART Transmit 132 // 133 if ( TXIF && TXIE ) 134 { 135 // Send byte from circular buffer to the UART 136 FSR0 = TxBufferUART + TxBufferPointerStartUART; 137 TxBufferPointerStartUART = ( TxBufferPointerStartUART + 1 ) % UART_BUFFER_LENGTH; 138 // Buffer empty? 139 if ( TxBufferPointerStartUART == TxBufferPointerEndUART ) 140 TXIE = FALSE; 141 // TX the byte 142 _TXREG = *FSR0; 143 } 144 145 // Return value does not matter 146 return Carry; 147 148 149 // ------------------------------------------------- 150 case DpaEvent_DpaRequest: 151 // Called to interpret DPA request for peripherals 152 // ------------------------------------------------- 153 // Peripheral enumeration 154 if ( IsDpaEnumPeripheralsRequest() ) 155 { 156 // We implement 1 user peripheral 157 _DpaMessage.EnumPeripheralsAnswer.UserPerNr |= 1; 158 FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_USER + 0 ); 159 _DpaMessage.EnumPeripheralsAnswer.HWPID |= 0x000F; 160 _DpaMessage.EnumPeripheralsAnswer.HWPIDver |= 0x0000; 161 162 DpaHandleReturnTRUE: 163 return TRUE; 164 } 165 // ------------------------------------------------- 166 // Get information about peripheral 167 else if ( IsDpaPeripheralInfoRequest() ) 168 { 169 if ( _PNUM == PNUM_USER + 0 ) 170 { 171 _DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_USER_AREA; 172 _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ_WRITE; 173 goto DpaHandleReturnTRUE; 174 } 175 176 break; 177 } 178 // ------------------------------------------------- 179 else 180 { 181 // Handle peripheral command 182 if ( _PNUM == PNUM_USER + 0 ) 183 { 184 // Check command 185 switch ( _PCMD ) 186 { 187 // ------------------------------ 188 // Write to UART 189 case 0: 190 // There must be some data to write 191 if ( _DpaDataLength == 0 ) 192 { 193 _ERROR_DATA_LEN: 194 DpaApiReturnPeripheralError( ERROR_DATA_LEN ); 195 } 196 197 // Pointer to data (setFSR1( _FSR_RF ) can be used too to save code) 198 FSR1 = &_DpaMessage.Request.PData[0]; 199 do 200 { 201 // Send one byte 202 TxUART( *FSR1++ ); 203 // Loop all bytes 204 } while ( --_DpaDataLength != 0 ); 205 206 // _DpaDataLength = 0 => no data returned 207 goto DpaHandleReturnTRUE; 208 209 // ------------------------------ 210 // Read from UART 211 case 1: 212 // No data must be sent 213 if ( _DpaDataLength != 0 ) 214 goto _ERROR_DATA_LEN; 215 216 // Pointer to the output buffer (setFSR1( _FSR_RF ) can be used too to save code) 217 FSR1 = &_DpaMessage.Response.PData[0]; 218 // Initial count of received bytes 219 _DpaDataLength = 0; 220 // Loop while there is enough space and some byte to read 221 while ( _DpaDataLength < sizeof( _DpaMessage.Response.PData ) && RxUART() ) 222 { 223 // Store read byte 224 setINDF1( W ); 225 // Move pointer 226 FSR1++; 227 // Count next byte 228 _DpaDataLength++; 229 } 230 231 // Return number of read bytes 232 goto DpaHandleReturnTRUE; 233 } 234 } 235 } 236 break; 237 238 // ------------------------------------------------- 239 case DpaEvent_Init: 240 // Do a one time initialization before main loop starts 241 242 // Connected TR pins (e.g. TR72D)? 243 moduleInfo(); 244 if ( !bufferINFO[5].7 ) 245 { 246 // Set them as inputs 247 TRISC.5 = 1; 248 TRISA.5 = 1; 249 TRISB.4 = 1; 250 } 251 252 // RX input 253 TRISC.7 = 1; 254 // TX output 255 TRISC.6 = 0; 256 257 #if !defined( TR7xD ) 258 UART1MD = 0; 259 unlockPPS(); 260 RC6PPS = 0x10; // TX (Note: RX does not have to be set, use default) 261 lockPPS(); 262 #endif 263 264 // Set baud rate 265 _SPBRGL = UART_SPBRG_VALUE( UART_BAUD ) & 0xff; 266 _SPBRGH = UART_SPBRG_VALUE( UART_BAUD ) >> 8; 267 // baud rate control setup: BRG16 = 1 268 #if !defined( TR7xD ) 269 setBAUD1CON( 0b0000.1.000 ); 270 #else 271 BAUDCON = 0b0000.1.000; 272 #endif 273 274 // CSRC TX9 TXEN SYNC SENDB BRGH TRMT TX9D 275 // TXEN = 1 276 // BRGH = 1 277 // async UART, high speed, 8 bit, TX enabled 278 #if !defined( TR7xD ) 279 setTX1STA( 0b0010.0100 ); 280 #else 281 TXSTA = 0b0010.0100; 282 #endif 283 284 // SPEN RX9 SREN CREN ADDEN FERR OERR RX9D 285 // SPEN = 1 286 // CREN = 1 287 // Continuous receive, enable port, 8 bit 288 _RCSTA = 0b1001.0000; 289 290 // Enable UART RX interrupt 291 RCIE = TRUE; 292 293 break; 294 295 // ------------------------------------------------- 296 case DpaEvent_AfterSleep: 297 // Called after woken up after sleep 298 299 TXIE = wasTXIE; 300 RCIE = TRUE; 301 break; 302 303 // ------------------------------------------------- 304 case DpaEvent_BeforeSleep: 305 // Called before going to sleep 306 307 // ------------------------------------------------- 308 case DpaEvent_DisableInterrupts: 309 // Called when device needs all hardware interrupts to be disabled (before Reset, Restart, LoadCode, Remove bond, and Run RFPGM) 310 311 wasTXIE = TXIE; 312 TXIE = FALSE; 313 RCIE = FALSE; 314 break; 315 } 316 317 return FALSE; 318 } 319 320 //############################################################################################ 321 // Note: make sure the parameter does not overlap another variable as the function is ready to be called from (timer) interrupt too 322 static uns8 _data; 323 void TxUART( uns8 data @ _data ) 324 //############################################################################################ 325 { 326 // Wait for a space in the buffer 327 while ( TXIE && TxBufferPointerStartUART == TxBufferPointerEndUART ); 328 329 // Disable TX interrupt 330 TXIE = FALSE; 331 // Compute pointer 332 FSR0 = TxBufferUART + TxBufferPointerEndUART; 333 // Optimization: TxBufferPointerEndUART = ( TxBufferPointerEndUART + 1 ) % UART_BUFFER_LENGTH; 334 TxBufferPointerEndUART++; 335 TxBufferPointerEndUART &= ~UART_BUFFER_LENGTH; 336 // Store byte 337 setINDF0( data ); 338 // Start transmitting 339 TXIE = TRUE; 340 } 341 342 //############################################################################################ 343 // W = read byte, Carry = result 344 bit RxUART() 345 //############################################################################################ 346 { 347 // Buffer empty? 348 if ( RxDataLengthUART == 0 ) 349 return FALSE; 350 351 // Disable RX interrupt 352 RCIE = FALSE; 353 // Get byte from the circular buffer 354 FSR0 = RxBufferUART + RxBufferPointerStartUART; 355 // Optimization: RxBufferPointerStartUART = ( RxBufferPointerStartUART + 1 ) % UART_BUFFER_LENGTH; 356 RxBufferPointerStartUART++; 357 RxBufferPointerStartUART &= ~UART_BUFFER_LENGTH; 358 // One byte less 359 RxDataLengthUART--; 360 // Returned byte 361 W = *FSR0; 362 // Enable RX interrupt 363 RCIE = TRUE; 364 // TRUE => byte was read 365 return TRUE; 366 } 367 368 //############################################################################################ 369 // 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) 370 #include "DPAcustomHandler.h" 371 //############################################################################################