| View previous topic :: View next topic | 
	
	
		| Author | Message | 
	
		| alan 
 
 
 Joined: 12 Nov 2012
 Posts: 358
 Location: South Africa
 
 
			    
 
 | 
			
				| Accessing only 1 byte of a SRF |  
				|  Posted: Fri Oct 11, 2013 12:02 am |   |  
				| 
 |  
				| Hi All. 
 How do I access only one byte of a SFR in a 16 bit PIC?
 
 
  	  | Code: |  	  | #word __P1DTCON1 = getenv("SFR:P1DTCON1") //PWM1 Dead time register1 
 | 
 For example I want to update only the high byte of P1DTCON1.
 
 For normal RAM I just use a struct and union.
 
 Regards
 |  | 
	
		|  | 
	
		| Ttelmah 
 
 
 Joined: 11 Mar 2010
 Posts: 19966
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Fri Oct 11, 2013 12:57 am |   |  
				| 
 |  
				| Look at #BIT and #BYTE 
 You can just use the struct and union though. If you 'pre-declare' a variable, then #byte can be used to locate _that variable_ at a location.
 The variable can be a structure, just as easily as any other variable type.
 So declare the structure and union as you would for RAM, then use:
 
 #byte variable_name = getenv("SFR:P1DTCON1") //PWM1 Dead time register1
 
 Which will then locate the variable called 'variable_name' at the specified location.
 
 Best Wishes
 |  | 
	
		|  | 
	
		| alan 
 
 
 Joined: 12 Nov 2012
 Posts: 358
 Location: South Africa
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Fri Oct 11, 2013 1:47 am |   |  
				| 
 |  
				| Thanks Ttelmah, 
 Didn't know you could do it that way.
 
 I started doing it as you suggested and the code are now shorter, however I still seem to misunderstand something as shown in the following code.
 
  	  | Code: |  	  | .................... typedef union { ....................  uint16_t WRD;
 ....................  struct {
 ....................    uint8_t High;
 ....................    uint8_t Low;
 ....................  }BTY;
 .................... } __DEADTIME;
 .................... __DEADTIME __DeadTimeREG;
 
 .................... void SetDeadTimeRegA(DutyCycle) { \
 ....................   __DeadTimeREG.BTY.Low &= (uint8_t)(0xC0);  /*Clr values*/ \
 *
 09B2:  MOV     81A,W4
 09B4:  LSR     W4,#8,W4
 09B6:  AND.B   #C0,W4L
 09B8:  MOV.B   W4L,W0L
 09BA:  MOV.B   W0L,81B
 
 | 
 Why does the compiler do a LSR and then do the AND in W4 move it W0 and then back to the byte?
 
 I don't think you would need more than this.
 
 Doesn't compile 	  | Code: |  	  | #asm MOV.B     __DeadTimeREG.BTY.Low,W0 AND.B   0xC0,W0
 MOV.B   W0,__DeadTimeREG.BTY.Low
 #endasm
 
 | 
  but hopefully you get the drift. 
 Probably doesn't make much difference the 2 extra instructions as it is a dsPIC33EP64FJ12MC202, but I like to understand for when I am in a jam regarding speed.
 
 Regards
 |  | 
	
		|  | 
	
		| FvM 
 
 
 Joined: 27 Aug 2008
 Posts: 2337
 Location: Germany
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Fri Oct 11, 2013 6:18 am |   |  
				| 
 |  
				| To avoid any overhead, define #BYTE registers 
 
  	  | Code: |  	  | #byte __P1DTCON1L = getenv("SFR:P1DTCON1") #byte __P1DTCON1H = getenv("SFR:P1DTCON1")+1
 | 
 |  | 
	
		|  | 
	
		| Ttelmah 
 
 
 Joined: 11 Mar 2010
 Posts: 19966
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Fri Oct 11, 2013 6:34 am |   |  
				| 
 |  
				| Second guessing why the assembler does things is often quite 'fun'.... 
 As an experiment, I tried changing the union to use a two char array, instead of the separate high/low defines.
 
 Code changes to:
 
  	  | Code: |  	  | union splitter {
 unsigned int16 word;
 char bytes[2];
 };
 
 union splitter __using_array;
 #byte __using_array = getenv("SFR:PMDOUT2") //PWM1 Dead time register1
 
 ....................    __using_array.bytes[1] &= (0xC0);
 0254:  MOV.B   PMDOUT2.7,W0L
 0256:  SE      W0,W0
 0258:  AND     #C0,W0
 025A:  MOV.B   W0L,PMDOUT2.7H
 
 | 
 
 If however the char is changed to 'unsigned', then using this or direct #byte defines, or the named array, then it always performs the 16bit access.
 
 It looks as if this is it's default way of accessing a 'byte' to give an empty top byte in the case of unsigned types....
 
 Best Wishes
 |  | 
	
		|  | 
	
		| Ttelmah 
 
 
 Joined: 11 Mar 2010
 Posts: 19966
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Fri Oct 11, 2013 12:39 pm |   |  
				| 
 |  
				|  	  | FvM wrote: |  	  | To avoid any overhead, define #BYTE registers 
 
  	  | Code: |  	  | #byte __P1DTCON1L = getenv("SFR:P1DTCON1") #byte __P1DTCON1H = getenv("SFR:P1DTCON1")+1
 | 
 | 
 
 Actually this does the same.....
 
 It appears it is CCS's default way of accessing a 'byte', if it is unsigned. It uses the rotation to clear the top byte, even if the result only uses the low byte. If signed, it uses SE instead.
 
 Best Wishes
 |  | 
	
		|  | 
	
		|  |