Parallel In Serial Out Shift Register-Revisited

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

hi every one ...feel free to delete this post if it is not logically !!!

I have posted my problem about interfacing PISO with Atmega128 i was so confused to clear the problem, However it does not matter.

I divide the problem into multiple part, i will try to solve each problem with your help.

in this part i have 60 byte frame, generated locally, this frame must be sent every 10 ms to porta connected directly to piso as in the attachment schematic.

there is 50 khz external interrupt (20 micro second) as external interrupt connected to PD0 of atmega128 and to CLK of piso, the Shift/Load pin of Piso connected To Pin5 of porte, the SER, CLK_INH, and CLR of PISO not used.

i have to wait until 10 ms as first run then i start the process, for each byte i need 8 interrupt(8*0.02 ms = 0.16 ms) after the first run, so for 60 byte i need (0.16 * 60 = 9.6 ms)  so i have a 0.4 ms free time in this free time i have to send what i call fix byte.

i simulate my work with PROTEUS, some thing go strange, there is a delay between 50 khz rising edge and Load enable(Pin5 of porte), it is about 7 microsecond, when i tried to put porta writing operation in the main loop and in the ISR just some flags the delay went to increase.

her is my code, some result, and schematic,  i do not know if it is good coding or at least correct coding.

can i trust PROTEUS IDE, How to achieve exactly 20 microsecond by Stimuli file in Atmel Studio 7?

is like this problem related to code optimization like using 16 bit global variable  (totalPulsCount)?

Atmega128 use 11095200 Crystal 

thank you for your attention .


#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/delay.h>
#include <stdbool.h>
#include <stdlib.h>
#define BitSet(ADDRESS, BIT) (ADDRESS |= (1<<BIT))
#define BitClear(ADDRESS, BIT) (ADDRESS &= ~(1<<BIT))
#define BitCheck(ADDRESS, BIT) (ADDRESS & (1<<BIT))
#define BitFlip(ADDRESS, BIT) (ADDRESS ^= (1<<BIT))
#define F_CPU 11095200
#define HEADER1 0xEB
#define HEADER2 0x90
#define ZERO_INSIDE 0x00
#define ONE_INSIDE 0xFF
#define TALIER 0x00
#define FIX_BYTE 0x00
#define MAXBYTES 60
#define MYUBRR F_CPU / (16L * USART_BAUDRATE) -1
static volatile uint8_t pulseCount = 0;
volatile uint16_t totalPulsCount = 0;
volatile bool first500Passed = false;
volatile bool fixByteFlag = false;
volatile uint8_t index_1 = 0;
volatile uint8_t calibFrame1[MAXBYTES];
void InterruptInit()
{
	EICRA |= (1 << ISC00) |(1 << ISC01);
	BitSet(EIMSK,INT0);
	BitClear(DDRD,DDD0);
	BitSet(PORTD,PD0);
}
void PortInit(void)
{
	PORTA = 0x00;
	DDRA = 0xFF;
	PORTB = 0x00;
	DDRB = 0xF8;
	DDRE = 0xFC;
	PORTE = 0x74;
}
void DefaultFrameInit(uint8_t byteToSend, volatile uint8_t tempArray[])
{
	uint8_t localIndex;
	tempArray[0] = HEADER1;
	tempArray[1] = HEADER2;
	tempArray[MAXBYTES - 1] = TALIER;
	for(localIndex = 2 ; localIndex < MAXBYTES -1; localIndex ++)
	{
		tempArray[localIndex] = byteToSend;
	}
}
int main(void)
{
    cli();
	DefaultFrameInit(ZERO_INSIDE, calibFrame1);
	PortInit();
	InterruptInit();
	sei();
    while (1)
    {
		BitSet(PORTE, PE5);
    }
}
ISR(INT0_vect)
{
	totalPulsCount++;
	if(totalPulsCount == 500)
	{
		totalPulsCount = 0;
		PORTA = calibFrame1[index_1];
		BitClear(PORTE, PE5);
		index_1++;
		pulseCount = 9;
		first500Passed = true;
		fixByteFlag = false;

	}
	if(first500Passed)
	{
		pulseCount--;
	}
	if (pulseCount == 0)
	{
		if(!fixByteFlag)
		{
			PORTA = calibFrame1[index_1];
			BitClear(PORTE, PE5);
			index_1++;
			pulseCount = 8;
			if(index_1 >= MAXBYTES)
			{
				index_1 = 0;
				fixByteFlag = true;
			}
		}
		else
		{
			PORTA = FIX_BYTE;
			BitClear(PORTE, PE5);
			pulseCount = 8;
		}
	}
}

 

Attachment(s): 

Last Edited: Mon. Mar 20, 2017 - 11:47 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

I can't see how the 166 is adding any value here. Not only could you bit bash it out a port pin, you also have the spi peripheral and the usart in sync mode.
7us doesn't seem too unreasonable. That's around 100 clocks and it takes probably most of that to enter the isr. I'd suggest looking at the alternatives i noted above and/or some hand crafted asm to speed things up. 20us is getting a tad fast, so you need to be concerned about execution time.

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

With GCC '-O1' optimisation this is the generated code

00000116 <__vector_1>:<br />
	}<br />
}<br />
ISR(INT0_vect)<br />
{<br />
 116:	1f 92       	push	r1<br />
 118:	0f 92       	push	r0<br />
 11a:	0f b6       	in	r0, 0x3f	; 63<br />
 11c:	0f 92       	push	r0<br />
 11e:	11 24       	eor	r1, r1<br />
 120:	0b b6       	in	r0, 0x3b	; 59<br />
 122:	0f 92       	push	r0<br />
 124:	2f 93       	push	r18<br />
 126:	8f 93       	push	r24<br />
 128:	9f 93       	push	r25<br />
 12a:	ef 93       	push	r30<br />
 12c:	ff 93       	push	r31<br />
	totalPulsCount++;<br />
 12e:	80 91 03 01 	lds	r24, 0x0103<br />
 132:	90 91 04 01 	lds	r25, 0x0104<br />
 136:	01 96       	adiw	r24, 0x01	; 1<br />
 138:	90 93 04 01 	sts	0x0104, r25<br />
 13c:	80 93 03 01 	sts	0x0103, r24<br />
	if(totalPulsCount == 500)<br />
 140:	80 91 03 01 	lds	r24, 0x0103<br />
 144:	90 91 04 01 	lds	r25, 0x0104<br />
 148:	84 3f       	cpi	r24, 0xF4	; 244<br />
 14a:	91 40       	sbci	r25, 0x01	; 1<br />
 14c:	c9 f4       	brne	.+50     	; 0x180 <__vector_1+0x6a><br />
	{<br />
		totalPulsCount = 0;<br />
 14e:	10 92 04 01 	sts	0x0104, r1<br />
 152:	10 92 03 01 	sts	0x0103, r1<br />
		PORTA = calibFrame1[index_1];<br />
 156:	e0 91 00 01 	lds	r30, 0x0100<br />
 15a:	f0 e0       	ldi	r31, 0x00	; 0<br />
 15c:	ea 5f       	subi	r30, 0xFA	; 250<br />
 15e:	fe 4f       	sbci	r31, 0xFE	; 254<br />
 160:	80 81       	ld	r24, Z<br />
 162:	8b bb       	out	0x1b, r24	; 27<br />
		BitClear(PORTE, PE5);<br />
 164:	1d 98       	cbi	0x03, 5	; 3<br />
		index_1++;<br />
 166:	80 91 00 01 	lds	r24, 0x0100<br />
 16a:	8f 5f       	subi	r24, 0xFF	; 255<br />
 16c:	80 93 00 01 	sts	0x0100, r24<br />
		pulseCount = 9;<br />
 170:	89 e0       	ldi	r24, 0x09	; 9<br />
 172:	80 93 05 01 	sts	0x0105, r24<br />
		first500Passed = true;<br />
 176:	81 e0       	ldi	r24, 0x01	; 1<br />
 178:	80 93 02 01 	sts	0x0102, r24<br />
		fixByteFlag = false;<br />
 17c:	10 92 01 01 	sts	0x0101, r1</p>
<p>	}<br />
	if(first500Passed)<br />
 180:	80 91 02 01 	lds	r24, 0x0102<br />
 184:	88 23       	and	r24, r24<br />
 186:	29 f0       	breq	.+10     	; 0x192 <__vector_1+0x7c><br />
	{<br />
		pulseCount--;<br />
 188:	80 91 05 01 	lds	r24, 0x0105<br />
 18c:	81 50       	subi	r24, 0x01	; 1<br />
 18e:	80 93 05 01 	sts	0x0105, r24<br />
	}<br />
	if (pulseCount == 0)<br />
 192:	80 91 05 01 	lds	r24, 0x0105<br />
 196:	81 11       	cpse	r24, r1<br />
 198:	23 c0       	rjmp	.+70     	; 0x1e0 <__vector_1+0xca><br />
	{<br />
		if(!fixByteFlag)<br />
 19a:	80 91 01 01 	lds	r24, 0x0101<br />
 19e:	81 11       	cpse	r24, r1<br />
 1a0:	1a c0       	rjmp	.+52     	; 0x1d6 <__vector_1+0xc0><br />
		{<br />
			PORTA = calibFrame1[index_1];<br />
 1a2:	e0 91 00 01 	lds	r30, 0x0100<br />
 1a6:	f0 e0       	ldi	r31, 0x00	; 0<br />
 1a8:	ea 5f       	subi	r30, 0xFA	; 250<br />
 1aa:	fe 4f       	sbci	r31, 0xFE	; 254<br />
 1ac:	80 81       	ld	r24, Z<br />
 1ae:	8b bb       	out	0x1b, r24	; 27<br />
			BitClear(PORTE, PE5);<br />
 1b0:	1d 98       	cbi	0x03, 5	; 3<br />
			index_1++;<br />
 1b2:	80 91 00 01 	lds	r24, 0x0100<br />
 1b6:	8f 5f       	subi	r24, 0xFF	; 255<br />
 1b8:	80 93 00 01 	sts	0x0100, r24<br />
			pulseCount = 8;<br />
 1bc:	88 e0       	ldi	r24, 0x08	; 8<br />
 1be:	80 93 05 01 	sts	0x0105, r24<br />
			if(index_1 >= MAXBYTES)<br />
 1c2:	80 91 00 01 	lds	r24, 0x0100<br />
 1c6:	8c 33       	cpi	r24, 0x3C	; 60<br />
 1c8:	58 f0       	brcs	.+22     	; 0x1e0 <__vector_1+0xca><br />
			{<br />
				index_1 = 0;<br />
 1ca:	10 92 00 01 	sts	0x0100, r1<br />
				fixByteFlag = true;<br />
 1ce:	81 e0       	ldi	r24, 0x01	; 1<br />
 1d0:	80 93 01 01 	sts	0x0101, r24<br />
 1d4:	05 c0       	rjmp	.+10     	; 0x1e0 <__vector_1+0xca><br />
			}<br />
		}<br />
		else<br />
		{<br />
			PORTA = FIX_BYTE;<br />
 1d6:	1b ba       	out	0x1b, r1	; 27<br />
			BitClear(PORTE, PE5);<br />
 1d8:	1d 98       	cbi	0x03, 5	; 3<br />
			pulseCount = 8;<br />
 1da:	88 e0       	ldi	r24, 0x08	; 8<br />
 1dc:	80 93 05 01 	sts	0x0105, r24<br />
		}<br />
	}<br />
}<br />
 1e0:	ff 91       	pop	r31<br />
 1e2:	ef 91       	pop	r30<br />
 1e4:	9f 91       	pop	r25<br />
 1e6:	8f 91       	pop	r24<br />
 1e8:	2f 91       	pop	r18<br />
 1ea:	0f 90       	pop	r0<br />
 1ec:	0b be       	out	0x3b, r0	; 59<br />
 1ee:	0f 90       	pop	r0<br />
 1f0:	0f be       	out	0x3f, r0	; 63<br />
 1f2:	0f 90       	pop	r0<br />
 1f4:	1f 90       	pop	r1<br />
 1f6:	18 95       	reti



From my calculations, there are 21 clock cycles to save the registers on entry,
then 16 cycles for the
	totalPulsCount++;<br />
	if(totalPulsCount == 500)<br />
	{<br />
	...<br />
	}

and 5 or 8 cycles for
	if(first500Passed)<br />
	{<br />
		pulseCount--;<br />
	}

then about 16 cycles for
	if (pulseCount == 0)<br />
	{<br />
		if(!fixByteFlag)<br />
		{<br />
			PORTA = calibFrame1[index_1];<br />
			BitClear(PORTE, PE5);

which sums to around 35 cycles.
At a F_CPU of 11095200 (really ?), that is about 3.5 us.


If I set no optimisation '-O0' I calculate the cycles to be over 70 cycles, which would produce your 7 us 'delay'.

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

Kartman wrote:
I can't see how the 166 is adding any value here. Not only could you bit bash it out a port pin, you also have the spi peripheral and the usart in sync mode.

Agreed - just seems to be a duplication of what's already in the MCU.

 

 

How to embed an image in a post: http://www.avrfreaks.net/wiki/em...

 

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

Please explain what do you mean exactly? it is existing hardware PISO used to stream bits to psk modulator

 

Last Edited: Tue. Mar 21, 2017 - 08:09 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Exactly? The AVR already has hardware built in that performs the same task as the 166. Using the inbuilt hardware might mean you only interrupt every 8 bits rather than every bit.

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

What we are saying is that it is pointless to have the external 74166 because the AVR already has that functionality built in

 

mjdwassouf wrote:
it is existing hardware PISO used to stream bits to psk modulator

Are you saying that you have an existing board with the external 74166 on it?

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

yes i have atmega128 with 166 PISO and i have to implement C code for it

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

do you mean I2C?

however i have to implement c code to present hardware.

I appreciate your suggestion, but i am obliged to an existing design.

 

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

No, I mentioned SPI or usart in synchronous mode. Read the datasheet and you'll see that they do much the same thing as your 166.

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

mjdwassouf wrote:
i am obliged to an existing design.

So, if it's an existing design, isn't there existing code to go with it??

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

no.no source for that design, however in spite of other easy design possibility i have to writ c code, what is your idea about my code?

i know that interfacing PISO is something from far past but not something impossible, maybe the next stage will be a new hardware design.

i thank you for your attention, you can help me with your experience related to what i have started this post

Last Edited: Tue. Mar 21, 2017 - 11:03 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You got your answer in#3.

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

To send a PISO byte from a Mega128, you need 12 pins. They should all be set to output. Eight pins make a Parallel port, and four pins are for controlling the '166.  The control lines are Master Reset, Parallel Enable, Clock, and Clock Enable.   Reset is active low.  Strobe this pin low once.  Put your data onto the parallel port. Now bring the other three pins low.

The data on the parallel port is shifted out (most significant bit first) each time that the clock line is made High, then make low again.  Wait 20 microseconds. Strobe this clock line eight times.  Your data has been shifted out.  Raise the Parallel Enable pin.  Load the next parallel data byte of the 80.  Lower the Parallel Enable pin and do the clock sequence.

  It takes 80 * 160 microSeconds (0.128 seconds) to send one complete frame of data.