| 
	
	|  |  |  
	
		| View previous topic :: View next topic |  
		| Author | Message |  
		| Backfire 
 
 
 Joined: 12 Oct 2020
 Posts: 48
 
 
 
			    
 
 | 
			
				| SPI Rx ISR and Timer ISRs |  
				|  Posted: Thu Jul 25, 2024 4:41 am |   |  
				| 
 |  
				| Hi all, I'm hoping someone can help me find an issue with some SPI code I'm trying to get working.
 
 I have a system of 4 PIC's (all PIC16F15356); One acting as an SPI master, three acting as slaves running the same code. I have successfully transferred data over the SPI from the master -> slaves, previously I had the code send three bytes of data, and the slaves would build these bytes into a message, then respond accordingly. This message building and further data manipulation was implemented in the main loop, after the SPI ISR had set a flag indicating data was available.
 
 Sometimes the slaves seemed to miss a message, so I have decided to transfer 32 bits of data, (with the MSB being a dummy 0x00 value). I have also moved the data manipulation into the ISR, as it's essentially just copying values received over the SPI into data structures.
 
 These values do seem to be collected correctly, but now another element of my code (stepper motor movement) no longer seems to run. This was called by a timer-controlled ISR again serviced in the main loop.
 
 I'm thinking my two ISR processes might be getting in the way of each other. I know that ISRs are supposed to contain the absolute minimum of processing (I previously made calls to make8(...) from my ISR), but all I'm doing now is bitwise operations and shifts, surely that's not "too much" to do in an ISR?
 
 I didn't think the timer ISR could be called while I was in the SPI Rx ISR, or can that happen with this PIC?
 
 Many thanks in advance for taking the time to read this.
 |  |  
		|  |  
		| temtronic 
 
 
 Joined: 01 Jul 2010
 Posts: 9588
 Location: Greensville,Ontario
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Thu Jul 25, 2024 8:19 am |   |  
				| 
 |  
				| others will KNOW, but is there a 'priority' sequence you may need to configure for which interrupt is '#1'. 
 Have seen reference to it here several times. CCS creates a 'table' ? with ALL of the possibles...maybe you need to create your own (3  or 4 ?) necessary. That will save time...
 |  |  
		|  |  
		| Ttelmah 
 
 
 Joined: 11 Mar 2010
 Posts: 19966
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Thu Jul 25, 2024 8:23 am |   |  
				| 
 |  
				| The PIC16 only supports one level of interrupts. So while you are inside an interrupt another cannot be serviced. The PIC18 does support two levels,
 while the DsPIC's support unlimited levels. This though gets more complex
 with 'levels' of interrupt priority, and only a higher level interrupt can
 interrupt a low level one. Interrupts on the same level cannot interrupt
 each other.
 However a second interrupt should be serviced as soon as you leave the
 handler for the first interrupt. This at heart is why the interrupt handling
 needs to be kept quick.
 Now it is difficult to know what is going on without seeing your code, but
 I'm slightly suspicious with your talk of a 32bit message, that your SPI
 handler may be staying inside the handler for more than one byte. If so,
 this will be a problem. An SPI interrupt means _one_ byte has been
 received, and just one byte should be read. Your SPI, should simply buffer
 the data, nothing else. Look at how ex_sisr handles serial receive.
 Bit shifts are quite slow, depending on how many bits are involved.
 However 'bitwise operations' may be slow or fast, depending on what
 you actually are doing. So a simple 'set a single predefined bit' operation
 uses just one instruction, but an operation saying 'set a bit using a
 variable to define which bit', uses dozens of operations. The PIC itself
 does not have an operator to do this, so a mask has to be rotated to
 select the right bit, and then logical operations are used to perform the
 actual operation. You can speed this type of thing massively by
 instead of using a counter, using your own mask. So (very much only an
 example):
 
  	  | Code: |  	  | void routine(void)
 {
 static int8 counter=1;
 static int8 value=0;
 
 if (something)
 bit_set(value,counter);
 
 counter++;
 if (counter==8)
 counter=1;
 }
 
 //Now compare with:
 void alternative(void)
 {
 static int8 mask=1;
 static int8 value=0;
 
 if (something)
 value|=mask;
 
 if (mask==128)
 mask=1;
 else
 mask>>=1
 }
 
 | 
 
 The former is about 20* slower than the latter!.....
 In the former, the compiler has to read the counter, then move a bit the
 number of locations specified by this, then OR this with the value.
 In the latter, there is a mask containing the required bit. This is simply
 OR'ed with the value. Then if it is not in the top bit, this is rotated once.
 Since this is a fixed one bit rotation, just uses one instruction. If it is
 in the top bit a new value replaces this in the low bit.
 
 Several big questions apply. How fast is your timer interrupt?. How fast
 is the SPI?. Are you possibly staying in the SPI handler for more than one
 byte?.
 
 Make8 is a fast instruction. However I cannot see why you would use this
 unless you have a larger value. If you are using something like make32,
 how fast this is again depends on whether it is involving fixed locations
 or variables.
 
 Things that are slow:
 Maths - particularly of higher types.
 Pointer accesses.
 Bit accesses involving variables.
 Waiting for things to arrive.
 
 Things that are quick.
 Reading a single byte.
 Basic logic.
 Integer addition and logic.
 Fixed rotations.
 
 The interrupt priority on the PIC16 only effects the order the interrupts
 are polled when an interrupt triggers.
 |  |  
		|  |  
		| Backfire 
 
 
 Joined: 12 Oct 2020
 Posts: 48
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Fri Jul 26, 2024 6:37 am |   |  
				| 
 |  
				| Hi Ttelmah, and thanks for such detailed advice. 
 I was right in thinking that there was only the most basic of interrupt handling on this device then, I've not yet used a PIC with multiple interrupt priorities!
 
 I was also apparently right to initially be transferring data a 'byte at a time', which I have reverted to, and seen my issue be solved.
 
 I must profess, the compiler documentation making reference to a default 'size' of 32 bits, in my mind (at least) made it seem as though an interrupt would only trigger when 32 bits had been received... A quick read of the datasheet shows this is not the case, and the SPI peripheral of course only works on 8 bit-wide data...
 
 I'll chalk this one up to odd examples in the compiler documentation.
 |  |  
		|  |  
		| Ttelmah 
 
 
 Joined: 11 Mar 2010
 Posts: 19966
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Fri Jul 26, 2024 10:26 am |   |  
				| 
 |  
				| Aaargh. 
 So you are using spi_xfer. OK. The 32bit thing is part of spi_xfer, not the
 interrupt. spi_xfer can transfer up to 32bit is a single spi transaction, but
 what is available to transfer is dependant on the hardware. Now using
 spi_xfer without interrupts, you can say 'transfer 32 bits', and it
 encapsulates the four byte transfers into a single operation. On the
 32bit PIC's these have multi byte SPI buffers and can support sending
 these bytes as one operation, but on the more basic PIC's the buffer is
 only one byte. Now you can tell spi_xfer to only transfer one byte, by
 simply telling it the number of bits in the transfer:
 
 byte_value=spi_xfer(YOUR_SPI, byte_to_send, 8);
 
 So no make8 needed.
   
 Key is that you always need to look at the hardware details for your PIC
 and understand that though the compiler can try to help, it is constrained
 by what the hardware supports.
 |  |  
		|  |  
		|  |  
  
	| 
 
 | You cannot post new topics in this forum You cannot reply to topics in this forum
 You cannot edit your posts in this forum
 You cannot delete your posts in this forum
 You cannot vote in polls in this forum
 
 |  
 Powered by phpBB © 2001, 2005 phpBB Group
 
 |