Strange behaviour of DIRSET on AVR128DA32

Go To Last Post
7 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm using the following code to set PORTD4 and PORTD5 as outputs:
 

VPORTD.DIR |= (1<<4);
VPORTD.DIR |= (1<<5);

This works as expected. When I change the code to

PORTD.DIRSET = (1<<4);
VPORTD.DIR |= (1<<5);

then only PORTD5 is set as output. When I print the value of PORTD.DIR, it shows 0x20. I have no idea why this happens.

 

Edit:

when I insert a nop, the problem is going away:

PORTD.DIRSET = (1<<4);
_NOP();
VPORTD.DIR |= (1<<5);
Last Edited: Sun. Sep 20, 2020 - 09:24 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, since they most likely use the same recipe as the other avr0/1 to create the Port peripheral, so I tried this on a mega4809. It appears there is a problem when using the bit special registers (I only tested DIRSET and OUTSET), followed by a sbi/cbi on the same register as the preceding bit operation fails. Place a nop in between as was done, then it works ok. Also tried on a 3217, same. A DA most likely not any different.

 

I would guess there is a problem with the way the SET/CLR/TGL works when followed by a cbi/sbi on the same target register. Probably an uncommon thing to use the V registers and the bit special registers back to back, but it seems to be a problem. Simple solution (use one or the other method), but they should probably spell out the potential problem in the datasheet. They probably don't even know the problem exists.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A third method is to write it this way:

PORTD.DIRSET = PIN5_bm | PIN4_bm;

Or like this:

VPORTD.DIR |= PIN5_bm | PIN4_bm;

The latter is using three instructions (in, ori, out) instead of two sbi instructions. Which method is better would depend on if you need the application to set them immediately or if it is ok with one cycle in between. 

I agree it should be mentioned in the Virtual Ports section of the datasheet. I would not be surprised if you see a note about this in some future datasheet updates :) Thank you for pointing our attention to this!

This did make me a bit curious, is there a use case where one could benefit from using PORTx.DIRSET/CLR/TGL and VPORTx.DIR (or OUT) back to back?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

echoromeo wrote:
is there a use case where one could benefit from using PORTx.DIRSET/CLR/TGL and VPORTx.DIR (or OUT) back to back?
I can't think of a reason for back to back but there's certainly a choice to be made. If it's single bits I image a VPORT based SBI is the best idea but if it's multiple bits one STS to PORT.DIRSET is presumably the more efficient?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes,   you get massive improvement to PORT speed with VPORT but lose the convenience of the write-only "steering" registers like DIRSET.

 

Be realistic.   You seldom change DIR directions but you will change OUT values millions of times.

You might use VPORT for a data bus but PORT for the (less frequently changed) control signals.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

echoromeo wrote:

This did make me a bit curious, is there a use case where one could benefit from using PORTx.DIRSET/CLR/TGL and VPORTx.DIR (or OUT) back to back?

There is no use case for using both VPORT.DIR and DIRSET, at least for me. I just replaced one of the VPORT.DIR instructions with PORTx.DIRSET because I was curious about the difference in the code size. The fact that my code didn't work anymore made me a bit nervous. I'm still not sure if there may be similar problems in addition to this PORT/VPORT case.

Last Edited: Mon. Sep 21, 2020 - 10:09 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yup, the simulator shows this behaviour too for the AVR-0/1.

 

Since they are based on the xmega, I was curious to see if the xmega also show this behaviour. I'm not familiar with xmega, but thanks to this thread I was able to translate the problematic code to xmega:

 

#include <avr/io.h>

int16_t main(void){
 // the following configurations are needed, VPorts are UNASSIGNED  upon reset....these must be placed PRIOR to making the above virtual pin changes
 PORTCFG.VPCTRLA=PORTCFG_VP0MAP_PORTA_gc|PORTCFG_VP1MAP_PORTB_gc; // assign the virtual ports A==>VP0, B==>VP1
 PORTCFG.VPCTRLB=PORTCFG_VP2MAP_PORTC_gc|PORTCFG_VP3MAP_PORTD_gc; // assign the virtual ports C==>VP2, D==>VP3
  
  PORTD.DIRSET = (1<<4);
  VPORT3.DIR |= (1<<5);
  
  while (1);
}

 

In the simulator, the xmega are free from this bug, both bits are set correctly. Someone messed up with the AVR-0/1 and broke what was working ok on the xmega.