USART Port Multiplexing ATtiny 1-series [ATtiny414]

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

Dear AVRFreaks community,

I build a µC chain using the ATtiny414. Each µC in the chain receives an UART string, pulls the information it needs out of the string and transmits the string to the next µC in the chain.

As seen in the Image "Block"

 

To realize this I am using the port multiplexing capability of the ATtiny414. The reception of the UART is driven by the receive completed interrupt.

An in addition to the initialization of the UART I make sure that the default pins of the UART are used.

 

I switch to the alternate UART pins in the receive completed interrupt routine and transfer the received Byte to a function,

which later should combine the Bytes to a String and after transmitting the String change back to the default pins of the UART.

At the moment I added numbers to have an indication, after which Byte the transition back to the default pins is done.

 

By the code written, I would expect that after the transmission of the number ‘3’

the systems changes back to the default pins and transmits through them the numbers ‘4’ to ’9’.

 

The real behaver of the µC is that he transmits the indication character ‘I’, the received byte in this case character ‘u’

and the numbers ‘0’, ’1’, ’7’, ’8’, ’9’ through the alternate pins of the UART and calls the receive complete interrupt routine again,

even thought there was no byte receive.  As seen in the Image "Outpul_Alternate_Pin"

 

I would expect that

 

InputStream(USART0.RXDATAL);               //Reading received data

 

clears the Flag by reading the received data, as stated in the datasheet:

 

“Bit 7 – RXCIF: USART Receive Complete Interrupt Flag

This flag is set to '1' when there are unread data in the receive buffer and cleared when the receive buffer is empty (i.e., does not contain any unread data).

When the Receiver is disabled, the receive buffer will be flushed and consequently the RXCIF will become zero.

 

When interrupt-driven data reception is used, the receive complete interrupt routine must read the received data from RXDATA in order to clear the RXCIF.

If not, a new interrupt will occur directly after the return from the current interrupt. ”

 

The numbers ‘2’ to ‘6’ are all transmitted through the default pins of the UART. As seen in the Image "Outpul_Default_Pin"

 

I am using Atmelstudio7 with the optimization lvl (-O1)

 


#include <avr/io.h>
//#include <util/delay.h>
#include <avr/interrupt.h>

#define F_CPU 3330000UL	// 33.3 MHz
#define BAUD_Rate (9600)
#define BAUD_Register_Value ((64UL * F_CPU)/(16UL * BAUD_Rate))

void InputStream (volatile unsigned char Data);
void USART_init(void)
{
	PORTMUX.CTRLB=PORTMUX_USART0_DEFAULT_gc;		//Use default UARTpins (2 takte)
	PORTB.OUTSET=PIN2_bm;						    //Set Pi2 on PortB (TX) high (_bm=BitMask)
	PORTA.OUTSET=PIN1_bm;
	PORTB.DIRSET=PIN2_bm;   						//Set Pin2 on PortB (TX) as Output
	PORTA.DIRSET=PIN1_bm;

	USART0.BAUD=BAUD_Register_Value;	    		//Set Baud rate

	USART0.CTRLA = USART_RXCIE_bm;			    	//Receive Complete Interrupt Enable everything els disabled

	USART0.CTRLB=	1<<USART_RXEN_bp			    //Receiver enabled
					|1<<USART_TXEN_bp			    //Transmitter enabled
					|0<<USART_SFDEN_bp		    	//Start frame detection disabled
					|0<<USART_ODME_bp			    //Open drain mode disabled
					|USART_RXMODE_NORMAL_gc		    //Normal mode, standard transmission speed
					|0<<USART_MPCM_bp;			    //Multi-processor communication mode disabled 

	USART0.CTRLC=	 USART_CMODE_ASYNCHRONOUS_gc    //Asynchrony USART mode
					|USART_PMODE_DISABLED_gc	    //No Parity
					|USART_SBMODE_1BIT_gc		    //1 Stop bit
					|USART_CHSIZE_8BIT_gc;		    //8 character bits
}

void USART_Transmit (volatile unsigned char* Data)
{
	while(!(USART0.STATUS & USART_DREIF_bm));	//Wait till transmit buffer ready
	USART0.TXDATAL= *Data;

}

ISR(USART0_RXC_vect)
{
	uint8_t test='I';
	PORTMUX.CTRLB=PORTMUX_USART0_ALTERNATE_gc;	// Output received data through alternate pins of UART
	USART_Transmit(&test);						// transmitting character I to show entry of interrupt routine
	InputStream(USART0.RXDATAL);				//Reading received data

}

void InputStream (volatile unsigned char Data)
{
	(((Data)&(1<<6)) ? (PORTA.OUTSET=(PIN3_bm)) : (PORTA.OUTCLR=(PIN3_bm))); // Check bit 6 in Data, if true SET els CLEAR Pin3 on Port A

	USART_Transmit(&Data);						// Send received Byte back
	Data=('0');//<<0x01);
	USART_Transmit(&Data);						//Data output for transition check
	Data=('1');//<<0x01);
	USART_Transmit(&Data);
	Data=('2');//<<0x01);
	USART_Transmit(&Data);
	Data=('3');//<<0x01);
	USART_Transmit(&Data);
	while(!(USART0.STATUS & USART_DREIF_bm));	//Wait till transmit buffer empty
	PORTMUX.CTRLB=PORTMUX_USART0_DEFAULT_gc;	//Output following data on default pins of UART
	Data=('4');//<<0x01);
	USART_Transmit(&Data);						//Data output for transition check
	Data=('5');//<<0x01);
	USART_Transmit(&Data);
	Data=('6');//<<0x01);
	USART_Transmit(&Data);
	Data=('7');//<<0x01);
	USART_Transmit(&Data);
	Data=('8');//<<0x01);
	USART_Transmit(&Data);
	Data=('9');//<<0x01);
	USART_Transmit(&Data);

}
int main(void)
{
    /* Replace with your application code */

	PORTA.DIRSET=PIN3_bm;		//Set Pin3 on PortA as Output
	USART_init();
	sei();	

    while (1)
    {

    }
}

Thanks for taking the time and every hint             

 

* Tags added

Attachment(s): 

This topic has a solution.
Last Edited: Tue. Sep 18, 2018 - 12:01 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I cannot help directly with your alternate-pin situation.  But if your app always uses a chain ("token ring"?), tell what you are using for line drivers -- i.e. the schematic.  I have several daisy-chain AVR8 apps, and use a single USART  -- RX connected upstream and TX connected downstream.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

I would expect that

 

InputStream(USART0.RXDATAL);               //Reading received data

 

clears the Flag by reading the received data, as stated in the datasheet:

 

Well, you are reading one byte, but, if the buffer has more data for some reason, the flag will not be cleared. The receive buffer can hold 2 bytes, plus one in the shift register, that's a total of 3 bytes that you may need to read before the flag clears.

Last Edited: Thu. Sep 13, 2018 - 04:20 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for your replys,

 

theusch wrote:
tell what you are using for line drivers

 

The ATtinys are in close proximity (less than 50 mm [5 cm]) and connected directly with each other on a PCB, so I don’t use any special line drivers.

 

El Tangas wrote:
if the buffer has more data for some reason, the flag will not be cleared.

 

That’s possible, and the datasheet is not clear on this, it only says “read the received data from RXDATA” and not RXDATAL

 

8.5.6 Accessing 16-bit Registers

They say „For a read operation, the low byte of the 16-bit register must be read before the high byte. When the low byte register is read by the CPU, the high byte of the 16-bit register is copied into the temporary register in the same clock cycle as the low byte is read. When the high byte is read, it is then read from the temporary register.“

 

On the other hand at 24.3.2.4 Data Reception - USART Receiver

“The receiver buffer can be read by reading RXDATA, comprising of DATA[7:0] in USART.RXDATAL, and DATA[8] in USART.RXDATAH. RXDATA should not be read unless the Receive Complete Interrupt Flag (RXCIF in USART.STATUS) is set. When using frames with fewer than eight bits, the unused most-significant bits are read as zero. If 9-bit characters are used, the ninth bit (DATA[8] in SART.RXDATAH) must be read before the low byte (DATA[7.0] in USART.RXDATAL).”

 

What I did:

 

I modified the code, so that it transmits the value of the USART0.STATUS register before and after the reading of USART0.RXDATAL the output is as seen in “Outpul_Alternate_Pin_witch_Statusregister”. Column 2 shows the values of the status register before the read operation and column 3 after. In the first line, this also shows the received ‘u’ character, the RXCIF bit is first set and after the read operation cleared. As would be expected.

But after that it is set again and does not clear. Furthermore the BDF bit is set.

“Bit 1 – BDF: Break Detected Flag

This bit is intended for USART configured to LINAUTO receive mode, see CTRLB. The break detector has a fixed threshold of 11 bits low for a BREAK to be detected. The BDF bit is set after a valid BREAK and SYNC character is detected. The bit is automatically cleared when next data is received. The bit will behave identically when USART is set to GENAUTO mode. In NORMAL or CLK2X receive mode, the BDF bit is unused.

This bit is cleared by writing a '1' to it.”

I expect that this should not have any effect since the UART is in NORMAL mode, but I am not sure.

The value of column 3, which is the received data stays NULL as expected.

I made some scope images to make sure there is no cross talk. There is something like a cross talk at the switching points of the pins (white rectangle), maybe a delay or at least a second stop bit is in order. I will investigate it further.

 

Thanks and keep the hints coming, they open up new few points and may help me or someone else finding a solution.

 

Scope picture description:

Top to bottom

RX pin  default

TX pin default

RX pin alternative

TX pin alternative

Decode of RX pin default (top signal)

Decode of TX pin default (second signal)

Decode of TX pin alternative (bottom signal)

 

*EDIT*

Modified source code to first read RXDATAH -> no change

see Terminal output. columne 2 show status register before read operation. columne 3 show RXDATAH. columne 4 show status register after read operation of RXDATAH and RXDATAL (image "Outpul_Alternate_Pin_witch_Statusregister2")

2 stop bits -> no change, crosstalke delayed by one bit, seems like delay is needed after changing pins and transmitting next data.

 

/*
 * Cido_Relais.c
 *
 * Created: 20.07.2018 13:18:09
 * Author : Boris
 */ 

#include <avr/io.h>
//#include <util/delay.h>
#include <avr/interrupt.h>


#define F_CPU 3330000UL	// 33.3 MHz
#define BAUD_Rate (9600)
#define BAUD_Register_Value ((64UL * F_CPU)/(16UL * BAUD_Rate))


void InputStream (volatile unsigned char Data);
void USART_init(void)
{
	PORTMUX.CTRLB=PORTMUX_USART0_DEFAULT_gc;		//Use default UARTpins (2 takte)
	PORTB.OUTSET=PIN2_bm;						//Set Pi2 on PortB (TX) high (_bm=BitMask)
	PORTA.OUTSET=PIN1_bm;
	PORTB.DIRSET=PIN2_bm;						//Set Pin2 on PortB (TX) as Output
	PORTA.DIRSET=PIN1_bm;
	
	USART0.BAUD=BAUD_Register_Value;			//Set Baud rate
	
	USART0.CTRLA = USART_RXCIE_bm;				//Receive Complete Interrupt Enable everything els disabled
	
								
	USART0.CTRLB=	1<<USART_RXEN_bp			//Receiver enabled
					|1<<USART_TXEN_bp			//Transmitter enabled
					|0<<USART_SFDEN_bp			//Start frame detection disabled
					|0<<USART_ODME_bp			//Open drain mode disabled
					|USART_RXMODE_NORMAL_gc		//Normal mode, standard transmission speed
					|0<<USART_MPCM_bp;			//Multi-processor communication mode disabled 
					
	USART0.CTRLC=	 USART_CMODE_ASYNCHRONOUS_gc//Asynchrony USART mode
					|USART_PMODE_DISABLED_gc	//No Parity
					|USART_SBMODE_2BIT_gc		//1 Stop bit
					|USART_CHSIZE_8BIT_gc;		//8 character bits 
}

void USART_Transmit (volatile unsigned char* Data)
{	
	while(!(USART0.STATUS & USART_DREIF_bm));	//Wait till transmit buffer ready
	USART0.TXDATAL= *Data;
	
	
}

ISR(USART0_RXC_vect)
{
	uint8_t test='I';
	PORTMUX.CTRLB=PORTMUX_USART0_ALTERNATE_gc;	// Output received data through alternate pins of UART 
	USART_Transmit(&test);						// transmitting character I to show entry of interrupt routine
	test=USART0.STATUS;							//Reading Status register of UART
	USART_Transmit(&test);						// transmitting Value of status register before reading data
	test=USART0.RXDATAH;
	USART_Transmit(&test);
	InputStream(USART0.RXDATAL);				//Reading received data
	
}


void InputStream (volatile unsigned char Data)
{
	uint8_t Value_Register=USART0.STATUS;	//Reading Status register of UART after reading Data
	USART_Transmit(&Value_Register);
	(((Data)&(1<<6)) ? (PORTA.OUTSET=(PIN3_bm)) : (PORTA.OUTCLR=(PIN3_bm))); // Check bit 6 in Data, if true SET els CLEAR Pin3 on Port A
	
	USART_Transmit(&Data);						// Send received Byte back	
	Data=('0');//<<0x01);
	USART_Transmit(&Data);						//Data output for transition check
	Data=('1');//<<0x01);
	USART_Transmit(&Data);
	Data=('2');//<<0x01);
	USART_Transmit(&Data);	
	Data=('3');//<<0x01);
	USART_Transmit(&Data);
	while(!(USART0.STATUS & USART_DREIF_bm));	//Wait till transmit buffer empty
	PORTMUX.CTRLB=PORTMUX_USART0_DEFAULT_gc;	//Output following data on default pins of UART
	Data=('4');//<<0x01);
	USART_Transmit(&Data);						//Data output for transition check
	Data=('5');//<<0x01);
	USART_Transmit(&Data);
	Data=('6');//<<0x01);
	USART_Transmit(&Data);
	Data=('7');//<<0x01);
	USART_Transmit(&Data);
	Data=('8');//<<0x01);
	USART_Transmit(&Data);
	Data=('9');//<<0x01);
	USART_Transmit(&Data);
	
}
int main(void)
{
    /* Replace with your application code */
		
	PORTA.DIRSET=PIN3_bm;		//Set Pin3 on PortA as Output
	USART_init();
	sei();	
	
    while (1) 
    {
		
    }
}

 

Attachment(s): 

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

I would read RXDATA again until the flag goes low. If the USART thinks it received a BREAK, does that appear as 0x00 data? Maybe the real data comes after.

Do a few extra reads and monitor the flags. Try to clear the break flag if it is set and see what happens.

 

The xtiny are new hardware, they may have silicon bugs we haven't discovered yet. Have you read the errata? Maybe this is known.

 

edit: where are the main and alternate RX pins connected? Are you sure none is floating or grounded?

Can you change pins to alternate and back while the USART is kept enabled? Maybe it generates spurious characters.

I don't know. The chip is new, there is much to test.

Last Edited: Fri. Sep 14, 2018 - 01:52 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for your replys,

 

El Tangas wrote:
If the USART thinks it received a BREAK, does that appear as 0x00 data?

El Tangas wrote:
Have you read the errata?

 

"Outpul_Alternate_Pin_witch_Statusregister2.PNG"  starting from second line  in the third columne  Bit 2 – FERR: Frame Error is set so the errata entry 40.1.1.5 USART may have helped.

 

El Tangas wrote:
Are you sure none is floating or grounded?

The reason for the interrupt loop was due to the floating/ low value on the alternate RxD pin as seen in DS1Z_QuickPrint5.png(third signal from the top).

This was read as a new Byte with the value \0 and trigger the receive complete interrupt.

 

The reason for the early switching to the default bin was due to the independent working of the UART. The UART was still transmitting data, when the register change occurred. 

This is fixed by:

//Wait till transmit is completed and data register is empty
while(!((USART0.STATUS & USART_TXCIF_bm)&&(USART0.STATUS & USART_DREIF_bm)));	

 

Furthermore  Bit 6 – TXCIF: USART Transmit Complete Interrupt Flag must be clear, since there is no transmit complete interrupt routine

/*This flag is automatically cleared when the transmit complete interrupt vector
is executed. The flag can also be cleared by writing a '1' to its bit location*/
USART0.STATUS|=USART_TXCIF_bm;	//No Interrupt call, clearing manual

So as often the biggest error was sitting in front of the keyboard. I was fixed on the code and did not consider the hardware enough.

Hopefully this post will at least help others by preventing the same mistakes.

 

Thanks for the time taken

 

This is the complete and working code:

#include <avr/io.h>
//#include <util/delay.h>
#include <avr/interrupt.h>

#define F_CPU 3333333UL	// 33.3 MHz
#define BAUD_Rate (9600)
#define BAUD_Register_Value ((64UL * F_CPU)/(16UL * BAUD_Rate))

void InputStream (volatile unsigned char Data);
void USART_init(void)
{
	PORTMUX.CTRLB=PORTMUX_USART0_DEFAULT_gc;		//Use default UARTpins

	//Set output value to high
	PORTB.OUTSET=PIN2_bm;
	PORTA.OUTSET=PIN1_bm;

	//Set pins as output
	PORTB.DIRSET=PIN2_bm;							// Set TxD on pin PB2 as output
	PORTA.DIRSET=PIN1_bm;							// Set TxD on pin PA1 as output

	//Set pins as input
	PORTB.DIRCLR=PIN3_bm;							//Set RxD on pin PB3 as input
	PORTA.DIRCLR=PIN2_bm;							//Set RxD on pin PA2 as input

	//Activate pull up
	PORTB.PIN3CTRL|=PORT_PULLUPEN_bm;
	PORTA.PIN2CTRL|=PORT_PULLUPEN_bm;

	USART0.BAUD=BAUD_Register_Value;			//Set Baud rate

	USART0.CTRLA = USART_RXCIE_bm;				//Receive Complete Interrupt Enable everything els disabled

	USART0.CTRLB=	1<<USART_RXEN_bp			//Receiver enabled
					|1<<USART_TXEN_bp			//Transmitter enabled
					|0<<USART_SFDEN_bp			//Start frame detection disabled
					|0<<USART_ODME_bp			//Open drain mode disabled
					|USART_RXMODE_NORMAL_gc		//Normal mode, standard transmission speed
					|0<<USART_MPCM_bp;			//Multi-processor communication mode disabled 

	USART0.CTRLC=	 USART_CMODE_ASYNCHRONOUS_gc//Asynchrony USART mode
					|USART_PMODE_DISABLED_gc	//No Parity
					|USART_SBMODE_1BIT_gc		//1 Stop bit
					|USART_CHSIZE_8BIT_gc;		//8 character bits
}

void USART_Transmit (volatile unsigned char* Data)
{
	while(!(USART0.STATUS & USART_DREIF_bm));	//Wait till transmit buffer ready
	USART0.TXDATAL= *Data;

}

ISR(USART0_RXC_vect)
{
	uint8_t test='I';

	PORTMUX.CTRLB=PORTMUX_USART0_ALTERNATE_gc;	// Output received data through alternate pins of UART
	USART_Transmit(&test);						// transmitting character I to show entry of interrupt routine
	InputStream(USART0.RXDATAL);				//Reading received data

}

void InputStream (volatile unsigned char Data)
{
	uint8_t Value_Register=USART0.STATUS;	//Reading Status register of UART after reading Data
	USART_Transmit(&Value_Register);
	(((Data)&(1<<6)) ? (PORTA.OUTSET=(PIN3_bm)) : (PORTA.OUTCLR=(PIN3_bm))); // Check bit 6 in Data, if true SET els CLEAR Pin3 on Port A

	USART_Transmit(&Data);						// Send received Byte back	

	Data=('0');//<<0x01);
	USART_Transmit(&Data);						//Data output for transition check

	Data=('1');//<<0x01);
	USART_Transmit(&Data);

	Data=('2');//<<0x01);
	USART_Transmit(&Data);	

	Data=('3');//<<0x01);
	USART_Transmit(&Data);

	while(!((USART0.STATUS & USART_TXCIF_bm)&&(USART0.STATUS & USART_DREIF_bm)));	//Wait till transmit is completed and data register is empty

	/*This flag is automatically cleared when the transmit complete interrupt vector is executed. The flag can
	also be cleared by writing a '1' to its bit location*/
	USART0.STATUS|=USART_TXCIF_bm;	//No Interrupt call, clearing manual

	PORTMUX.CTRLB=PORTMUX_USART0_DEFAULT_gc;	//Output following data on default pins of UART

	Data=('4');//<<0x01);
	USART_Transmit(&Data);						//Data output for transition check

	Data=('5');//<<0x01);
	USART_Transmit(&Data);

	Data=('6');//<<0x01);
	USART_Transmit(&Data);

	Data=('7');//<<0x01);
	USART_Transmit(&Data);

	Data=('8');//<<0x01);
	USART_Transmit(&Data);

	Data=('9');//<<0x01);
	USART_Transmit(&Data);

	while(!((USART0.STATUS & USART_TXCIF_bm)&&(USART0.STATUS & USART_DREIF_bm)));	//Wait till transmit is completed and data register is empty
	/*This flag is automatically cleared when the transmit complete interrupt vector is executed. The flag can
	also be cleared by writing a '1' to its bit location*/
	USART0.STATUS|=USART_TXCIF_bm;	//No Interrupt call, clearing manual

}
int main(void)
{
    /* Replace with your application code */

	PORTA.DIRSET=PIN3_bm;		//Set Pin3 on PortA as Output
	USART_init();
	sei();	

    while (1)
    {

    }
}