MKL27Z64: Doubt about using PTA3 as GPIO

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

MKL27Z64: Doubt about using PTA3 as GPIO

Jump to solution
1,774 Views
RicardoRuiz18a
Contributor II

Hi.

I recently designed a test pcb for this MCU, the way i program the pcb is through USB port so i'm not using  the SWD port and have it disconnected, but i want/need to use this pin as GPIO it's default is SWD_DIO. The problem is when i configure that port to work as GPIO by writing '1' in the mux it just does not goes to 'o' logic i'm always getting high as output.

This is how i'm setting ports as outputs:

SIM_SCGC5 |= SIM_SCGC5_PORTB_MASK// Turn on the port.
SIM_SCGC5 |= SIM_SCGC5_PORTA_MASK

PORTB_PCR19 |= PORT_PCR_MUX(1);// select ALT 1 of mux (GPIO)
PORTB_PCR18 |= PORT_PCR_MUX(1);// 20
PORTA_PCR3 |= PORT_PCR_MUX(1);// 11

GPIOB_PDDR |= 1<<19;
GPIOB_PDDR |= 1<<18;
GPIOA_PDDR |= 1<<3;

Then in my program i use PSOR, PCOR, PTOR, PTB19 and PTB18 correctly change it's state, but PTA3 do nothing. I was thinking the reason for it is that this pin has an internal pullup resistor, but the reference manual does not give information about it.

It is possible to use this PTA3 as GPIO? Or which is the reason that i can't change the state to low?.

Thank you.

0 Kudos
1 Solution
1,729 Views
bobpaddock
Senior Contributor III

I regularly use the SWD CLK and DIO pins as outputs for debugging markers. 
The code is below, for GCC.

Do not use the OR Assignment operator '|=' indiscriminately, despite NXP showing it in examples far to often.  At best it wastes code space and at worse you don't get what you expect for the register.

/* Change bit to match your hardware, if needed: */
#define SWD_CLK_bp (0UL)
#define SWD_DIO_bp (3UL)

#define ATTR_NO_INSTRUMENT_FUNCTION __attribute__( ( no_instrument_function ) )

/* ---- */
#define SWD_CLK_bm (1UL << SWD_CLK_bp)

static inline ATTR_NO_INSTRUMENT_FUNCTION void SWD_CLK_ASSERT( void )
{
  GPIOA_PSOR = SWD_CLK_bm;
}

static inline ATTR_NO_INSTRUMENT_FUNCTION void SWD_CLK_DEASSERT( void )
{
  GPIOA_PCOR = SWD_CLK_bm;
}

static inline ATTR_NO_INSTRUMENT_FUNCTION void SWD_CLK_TOGGLE( void )
{
  GPIOA_PTOR = SWD_CLK_bm;
}

static inline ATTR_NO_INSTRUMENT_FUNCTION uint8_t SWD_CLK_ASSERTED( void )
{
  return( 0U != (GPIOA_PDIR & SWD_CLK_bm) );
}

static inline ATTR_NO_INSTRUMENT_FUNCTION uint8_t SWD_CLK_DEASSERTED( void )
{
  return( 0U == (GPIOA_PDIR & SWD_CLK_bm) );
}

static inline ATTR_NO_INSTRUMENT_FUNCTION void SWD_CLK_INIT( void )
{
  PORTA_PCR0 = PORT_PCR_MUX( 1U );
  GPIOA_PCOR = SWD_CLK_bm;
  GPIOA_PDDR |= SWD_CLK_bm;
}

/* ---- */
#define SWD_DIO_bm (1UL << SWD_DIO_bp)

static inline ATTR_NO_INSTRUMENT_FUNCTION void SWD_DIO_ASSERT( void )
{
  GPIOA_PSOR = SWD_DIO_bm;
}

static inline ATTR_NO_INSTRUMENT_FUNCTION void SWD_DIO_DEASSERT( void )
{
  GPIOA_PCOR = SWD_DIO_bm;
}

static inline ATTR_NO_INSTRUMENT_FUNCTION void SWD_DIO_TOGGLE( void )
{
  GPIOA_PTOR = SWD_DIO_bm;
}

static inline ATTR_NO_INSTRUMENT_FUNCTION uint8_t SWD_DIO_ASSERTED( void )
{
  return( 0U != (GPIOA_PDIR & SWD_DIO_bm) );
}

static inline ATTR_NO_INSTRUMENT_FUNCTION uint8_t SWD_DIO_DEASSERTED( void )
{
  return( 0U == (GPIOA_PDIR & SWD_DIO_bm) );
}

static inline ATTR_NO_INSTRUMENT_FUNCTION void SWD_DIO_INIT( void )
{
  PORTA_PCR3 = PORT_PCR_MUX( 1U );
  GPIOA_PCOR = SWD_DIO_bm;
  GPIOA_PDDR |= SWD_DIO_bm;
}

int main( void )
{
  SIM_SCGC5 |= SIM_SCGC5_PORTA_MASK;

  SWD_CLK_INIT();
  SWD_DIO_INIT();

  SWD_DIO_TOGGLE(); /* Make DIO and CLK toggle out of phase */

for(;;)
 {
  SWD_CLK_TOGGLE();
  SWD_DIO_TOGGLE();
 }
}

 

View solution in original post

7 Replies
1,730 Views
bobpaddock
Senior Contributor III

I regularly use the SWD CLK and DIO pins as outputs for debugging markers. 
The code is below, for GCC.

Do not use the OR Assignment operator '|=' indiscriminately, despite NXP showing it in examples far to often.  At best it wastes code space and at worse you don't get what you expect for the register.

/* Change bit to match your hardware, if needed: */
#define SWD_CLK_bp (0UL)
#define SWD_DIO_bp (3UL)

#define ATTR_NO_INSTRUMENT_FUNCTION __attribute__( ( no_instrument_function ) )

/* ---- */
#define SWD_CLK_bm (1UL << SWD_CLK_bp)

static inline ATTR_NO_INSTRUMENT_FUNCTION void SWD_CLK_ASSERT( void )
{
  GPIOA_PSOR = SWD_CLK_bm;
}

static inline ATTR_NO_INSTRUMENT_FUNCTION void SWD_CLK_DEASSERT( void )
{
  GPIOA_PCOR = SWD_CLK_bm;
}

static inline ATTR_NO_INSTRUMENT_FUNCTION void SWD_CLK_TOGGLE( void )
{
  GPIOA_PTOR = SWD_CLK_bm;
}

static inline ATTR_NO_INSTRUMENT_FUNCTION uint8_t SWD_CLK_ASSERTED( void )
{
  return( 0U != (GPIOA_PDIR & SWD_CLK_bm) );
}

static inline ATTR_NO_INSTRUMENT_FUNCTION uint8_t SWD_CLK_DEASSERTED( void )
{
  return( 0U == (GPIOA_PDIR & SWD_CLK_bm) );
}

static inline ATTR_NO_INSTRUMENT_FUNCTION void SWD_CLK_INIT( void )
{
  PORTA_PCR0 = PORT_PCR_MUX( 1U );
  GPIOA_PCOR = SWD_CLK_bm;
  GPIOA_PDDR |= SWD_CLK_bm;
}

/* ---- */
#define SWD_DIO_bm (1UL << SWD_DIO_bp)

static inline ATTR_NO_INSTRUMENT_FUNCTION void SWD_DIO_ASSERT( void )
{
  GPIOA_PSOR = SWD_DIO_bm;
}

static inline ATTR_NO_INSTRUMENT_FUNCTION void SWD_DIO_DEASSERT( void )
{
  GPIOA_PCOR = SWD_DIO_bm;
}

static inline ATTR_NO_INSTRUMENT_FUNCTION void SWD_DIO_TOGGLE( void )
{
  GPIOA_PTOR = SWD_DIO_bm;
}

static inline ATTR_NO_INSTRUMENT_FUNCTION uint8_t SWD_DIO_ASSERTED( void )
{
  return( 0U != (GPIOA_PDIR & SWD_DIO_bm) );
}

static inline ATTR_NO_INSTRUMENT_FUNCTION uint8_t SWD_DIO_DEASSERTED( void )
{
  return( 0U == (GPIOA_PDIR & SWD_DIO_bm) );
}

static inline ATTR_NO_INSTRUMENT_FUNCTION void SWD_DIO_INIT( void )
{
  PORTA_PCR3 = PORT_PCR_MUX( 1U );
  GPIOA_PCOR = SWD_DIO_bm;
  GPIOA_PDDR |= SWD_DIO_bm;
}

int main( void )
{
  SIM_SCGC5 |= SIM_SCGC5_PORTA_MASK;

  SWD_CLK_INIT();
  SWD_DIO_INIT();

  SWD_DIO_TOGGLE(); /* Make DIO and CLK toggle out of phase */

for(;;)
 {
  SWD_CLK_TOGGLE();
  SWD_DIO_TOGGLE();
 }
}

 

1,700 Views
myke_predko
Senior Contributor III

Hey @bobpaddock 

Could you expand on your comment "OR Assignment operator '|=' indiscriminately ... at worse you don't get what you expect for the register."? 

What exactly are the issues (I haven't looked at the generated code and I'm wondering if what's generated is different in different situations).  

Should the statements be:

Register = Register | Constant; 

Rather than:

Register |= Constant;

?

0 Kudos
1,684 Views
bobpaddock
Senior Contributor III

It is the difference between OR-Assignment vs Assignment that I'm referring too, rather than the two ways you explain of doing OR-Assignment.

In the ARM line a lot of the registers are "Write '1' to clear" ('W1C' in the data sheets register notes) a bit in a status register.

If a bit is already set and you are trying to clear a different bit by writing a '1' to it, that OTHER set bit gets cleared and lost.  This can make for hair pulling bugs where you end up with things that appear to be lost interrupts for example.

In the case of this thread most of the pull-bits for PORTA are zero by default.  This particular bit is one by default, so using |= propagated the unwanted pull up.

For reasons unknown to me Freescale/NXP uses |= in their examples when they really shouldn't.  Leading  many users to copy the examples as "the right way".



1,678 Views
myke_predko
Senior Contributor III

@bobpaddock 

Gotcha - I haven't thought about that since 8 Bit days when input & output registers were paired to minimize address space issues.  

I would have thought the chance for that was designed out of (fairly new) processors like ARM.  

Thanx for taking the time to reply and explain.

myke

0 Kudos
1,716 Views
RicardoRuiz18a
Contributor II

This is how i make it work, since i notice that operator |= as you say i was not getting what i expected. 

SIM_SCGC5 |= SIM_SCGC5_PORTA_MASK;//ENCENDER PUERTO A

PORTA_PCR3 = 0x00000100; // SWD_DIO

PORTA_PCR0 = 0x00000100; // SWD_CLK

GPIOA_PDDR |= 1<<3;
GPIOA_PDDR |= 1<<0;

The only thing i changed was the assigment of PCR by manually writting the  value. Could you please tell me the reason that is not good practical the use of |=? What would you recommend to use instead.

Thank you.

 

0 Kudos
1,706 Views
bobpaddock
Senior Contributor III

"Could you please tell me the reason that is not good practical the use of |=?"

The OR-assignment operator will first read the register, then OR in the constant, then write the new value back out to the register.

In most cases this simply wastes a bit of time from the unneeded Read and OR.
It has the potential to increase code space, and this is device dependent.

The two places that it can cause problems is that if a read of register, say a status register, causes some bit to change its value.  This could cause problems with lost bytes in a UART for example.  Again this is device dependent.

In the case at hand here the state of the other bits in the register are unknown (unless you like reading datasheets in depth) and the Pull Up/Down bits could be enabled among other bits. So it is better to use assignment ('=') to get the bits you want and ONLY the bits you want set.

 

0 Kudos
1,737 Views
danielchen
NXP TechSupport
NXP TechSupport

Hi

Please refer to reference manual.   SWD_DIO is pulled up internally, should be disabled.

 

danielchen_0-1622623493959.png

 

Regards

Daniel