View previous topic :: View next topic |
Author |
Message |
marklamond
Joined: 29 Aug 2004 Posts: 7
|
Posted: Tue Jul 08, 2008 6:47 pm Post subject: Shift out bits with external clock |
|
|
Hi there,
Can anyone suggest a way of shifting out a number bits with reference to an external clock?
The SHIFTIN/OUT command only has options to generate its own clock, not receive one.
Does anyone have any suggestions? I guess i could use a shift register on one of the output ports, but I would rather not use any external hardware as it seems a little untidy.
Any suggestions would be much appreciated,
Edit - i did some more searching and found this post:
http://www.mcselec.com/index2.php?option=com_forum&Itemid=59&page=viewtopic&t=5577
I'm now looking into the direction of hardware SPI, that seems to fit the bill perfectly. No point bit bashing when you can use the proper tools for the job!
Thanks, |
|
Back to top |
|
|
Evert :-)
Joined: 18 Feb 2005 Posts: 2156
|
|
Back to top |
|
|
marklamond
Joined: 29 Aug 2004 Posts: 7
|
Posted: Thu Jul 10, 2008 1:18 am Post subject: |
|
|
Hi there,
The device i wish to send the data to is some programmable logic.
I simply need to shift out some bytes from my AVR when a pin goes high. The bytes need to be shifted out in sync with an external clock generated by my logic which is either 2,4 or 8 mhz.
I have never used SPI before and am still learning about it, it would appear that i should use it in slave mode so i can accept an external clock. |
|
Back to top |
|
|
AdrianJ
Joined: 16 Jan 2006 Posts: 2483 Location: Queensland
|
Posted: Thu Jul 10, 2008 2:42 am Post subject: |
|
|
Yes, the SPIIN command is what you need, after setting the SPI system to slave mode. You also have to set the clock phase and polarity to match your incoming signals.
Be aware that the max SPI clock frequency is 1/4 of the system clock in an AVR, so to get 2 MHz SPI clock, you will need to run the processor at 8 MHz at least. More will work, the SPI will sync with whatever clock speed it sees, but you must be above the minimum. _________________ Adrian Jansen
Computer language is a framework for creativity |
|
Back to top |
|
|
marklamond
Joined: 29 Aug 2004 Posts: 7
|
Posted: Sat Oct 25, 2008 12:23 am Post subject: |
|
|
I'm back on this - don't you mean SPIOUT ? I want to shift some bits out, not recieve them?
After doing some reading i don't think SPI is suitable for what i want to do, it seems that to shift some bits out i need to send some in from the master, as well as a clock? I don't have a master device, i simply want to shift some bits out in sync with an external clock.
I think the only way i can do this is with an external parallel in, serial out shift register, and use the AVR to load that with what i want to send. |
|
Back to top |
|
|
Luciano
Joined: 29 Nov 2004 Posts: 3149 Location: Italy
|
Posted: Sat Oct 25, 2008 8:38 am Post subject: |
|
|
marklamond wrote: | I simply want to shift some bits out in sync with an external clock. |
Hi,
Just use one pin as input for the external clock and one pin as
output to send out your bits. The code to implement that should
be quite simple, just a loop where you check the input pin (external clock)
and based on what you have on the clock line you send out your bits one
after the other with the output pin.
Here you can see an oscilloscope trace of a Bascom Shiftout:
http://www.mcselec.com/index2.php?option=com_forum&Itemid=59&page=viewtopic&t=6525
Best regards,
Luciano |
|
Back to top |
|
|
marklamond
Joined: 29 Aug 2004 Posts: 7
|
Posted: Sat Oct 25, 2008 4:31 pm Post subject: |
|
|
Hi Luciano, thanks for the reply.
I have the following program:
Code: |
'-------------------------------------------------------------------------------
'Compiler Directives
'-------------------------------------------------------------------------------
$crystal = 16000000 'set crystal speed
$regfile = "m8def.dat" 'set type of chip
$baud = 9600 'set com1 baud rate
'-------------------------------------------------------------------------------
'Configure Hardware
'-------------------------------------------------------------------------------
Config Pinb.0 = Output 'set pinb.0 as output
Config Pind.7 = Input 'set pind.7 as input
'-------------------------------------------------------------------------------
'Main Program
'-------------------------------------------------------------------------------
Do
Select Case Pind.7 'read pind.7
Case 0 : Reset Portb.0
Case 1 : Set Portb.0
End Select
Loop
|
Feeding in a 2mhz clock, the chip is unable to track the incoming pulses and goes crazy. It would seem that even running at 16mhz i don't have enough clock cycles to do what i need to? Perhaps doing it in assembly is the only way?
Out of interest, i tried this:
Code: | '-------------------------------------------------------------------------------
'Compiler Directives
'-------------------------------------------------------------------------------
$crystal = 16000000 'set crystal speed
$regfile = "m8def.dat" 'set type of chip
$baud = 9600 'set com1 baud rate
'-------------------------------------------------------------------------------
'Configure Hardware
'-------------------------------------------------------------------------------
Config Pinb.0 = Output 'set as output
'-------------------------------------------------------------------------------
'Main Program
'-------------------------------------------------------------------------------
'Main Loop Starts
Do
$asm
sbi portb, 0
cbi portb, 0
$end Asm
Loop
'Main Loop Ends |
I can almost generate 2mhz (will check on the scope later), but that is without asking the cpu to do anything else. If i can't generate 2mhz, then surely I’ve no chance of reading the clock and shifting bits out quickly enough? I guess the loop is probably using more clock cycles than it would in asm.
Please excuse my ignorance if i'm missing something obvious! |
|
Back to top |
|
|
DToolan
Joined: 14 Aug 2004 Posts: 1384 Location: Dallas / Fort Worth, Texas (USA)
|
Posted: Sun Oct 26, 2008 9:51 pm Post subject: |
|
|
Try hardware SPI in slave mode. The data-in line to the AVR can be tied high / low or left floating since you aren't sending data from the external device. Tie the AVR SS pin to ground if your external device does not generate a chip select.
Code: |
$regfile = "m8def.dat"
$crystal = 16000000
$baud = 9600
$hwstack = 32
$swstack = 32
$framesize = 40
DIM Old_DataPointer As Byte
DIM New_DataPointer As Byte
DIM SPI_DataOut(8) As Byte
SPI_DataOut(1) = 1
SPI_DataOut(2) = 2
SPI_DataOut(3) = 3
SPI_DataOut(4) = 4
SPI_DataOut(5) = 5
SPI_DataOut(6) = 6
SPI_DataOut(7) = 7
SPI_DataOut(8) = 8
Old_DataPointer = 1 : New_DataPointer = 1
SPCR = &b11000000 : SPDR = SPI_DataOut(1)
' ^^^^^^^^
' ||||||||_ CLOCKRATE - of no consequence in slave mode since the AVR does not generate clock (clock is an input pin)
' ||||||___ PHASE - 0 = sample data-in on rising edge of clock, 1 = sample data-in on falling edge of clock
' |||||____ POLARITY - of no consequence in slave mode since the AVR does not generate clock (clock is an input pin)
' ||||_____ MASTER/SLV - 0 = SLAVE, 1 = MASTER
' |||______ DATA ORDER - 0 = transmit (data-out) MSB first, 1 = transmit (data-out) LSB first
' ||_______ SPI ENABLE - 0 = disabled, 1 = enabled
' |________ SPI INT EN - 0 = SPI interrupt disabled, 1 = SPI interrupt enabled
ON SPI SPI_DataOut NOSAVE : ENABLE INTERRUPTS
'MAIN
DO
IF Old_DataPointer <> New_DataPointer THEN 'data for external device was placed into SPDR
INCR SPI_DataOut(Old_DataPointer) 'increment the value in that old buffer position
Old_DataPointer = New_DataPointer 'equalize the pointer values
ENDIF
LOOP
'***************************************
SPI_DataOut:
PUSH R10
PUSH R11
PUSH R16
PUSH R24
PUSH R26
PUSH R27
IN R24, SREG
PUSH R24
INCR New_DataPointer
IF New_DataPointer = 9 THEN
New_DataPointer = 1
ENDIF
'fill SPDR with the next byte for him to take
SPDR = SPI_DataOut(New_DataPointer)
POP R24
!OUT SREG, R24
POP R27
POP R26
POP R24
POP R16
POP R11
POP R10
RETURN |
|
|
Back to top |
|
|
Luciano
Joined: 29 Nov 2004 Posts: 3149 Location: Italy
|
Posted: Mon Oct 27, 2008 4:35 pm Post subject: |
|
|
Hi,
(Sorry, I didn't see that the clock was 2.4 or 8 MHz).
If the clock is 2.4 MHz, then a software only approach is not possible.
See the solution posted by DToolan using the SPI interface of the AVR.
Best regards,
Luciano |
|
Back to top |
|
|
marklamond
Joined: 29 Aug 2004 Posts: 7
|
Posted: Tue Oct 28, 2008 2:12 am Post subject: |
|
|
Many thanks for the code snippet, that has helped a lot!
I now have data out of the MISO pin using a signal generator for the clock.
However if i exceed 160khz on the clock it seems to loose track of it and the output stays high. Drop the crystal down to 8mhz and the same happens at 80khz.
That's not 1/4 of the system clock? Is this because of the ISR? |
|
Back to top |
|
|
DToolan
Joined: 14 Aug 2004 Posts: 1384 Location: Dallas / Fort Worth, Texas (USA)
|
Posted: Tue Oct 28, 2008 4:19 am Post subject: |
|
|
So let me ask then... are you expecting to pump data out of this AVR at a continuous clock rate (no pause between bytes) of 2 MHz? This would give approx 500ns (or less) to update SPDR with the next byte to send out.
The clock rate (for bits out per byte) can be done... but I don't see a continual 2 MHz, non-pausing stream as realistic. Did you expect to do anything else with this AVR besides provide a continual data stream of 2 Mbps?
This would be about the fastest I can imagine for a continual data stream...
Code: | $regfile = "m8def.dat"
$crystal = 16000000
$baud = 9600
$hwstack = 32
$swstack = 32
$framesize = 40
DIM SPI_DataOut As Byte
SPI_DataOut = 0
SPCR = &b11000000 : SPDR = SPI_DataOut
' ^^^^^^^^
' ||||||||_ CLOCKRATE - of no consequence in slave mode since the AVR does not generate clock (clock is an input pin)
' ||||||___ PHASE - 0 = sample data-in on rising edge of clock, 1 = sample data-in on falling edge of clock
' |||||____ POLARITY - of no consequence in slave mode since the AVR does not generate clock (clock is an input pin)
' ||||_____ MASTER/SLV - 0 = SLAVE, 1 = MASTER
' |||______ DATA ORDER - 0 = transmit (data-out) MSB first, 1 = transmit (data-out) LSB first
' ||_______ SPI ENABLE - 0 = disabled, 1 = enabled
' |________ SPI INT EN - 0 = SPI interrupt disabled, 1 = SPI interrupt enabled
'ON SPI SPI_DataOut NOSAVE : ENABLE INTERRUPTS
'MAIN
CLR R24
SPI_Test:
SBIS SPSR, 7 'test for byte transfer complete
JMP SPI_Test 'not complete
SPI_Fill:
!OUT SPDR, R24 'fill SPI data out shift register
INC R24 'increment filler byte
JMP SPI_Test 'go back and test for done
'*************************************** |
|
|
Back to top |
|
|
Luciano
Joined: 29 Nov 2004 Posts: 3149 Location: Italy
|
Posted: Tue Oct 28, 2008 10:19 am Post subject: |
|
|
Hi,
Can you please describe your circuit?
Which device is sending the data to the AVR?
Why not generate the clock with the AVR?
Best regards,
Luciano |
|
Back to top |
|
|
marklamond
Joined: 29 Aug 2004 Posts: 7
|
Posted: Wed Oct 29, 2008 12:14 am Post subject: |
|
|
I'll try and explain things better, many thanks for your help.
The custom logic device i am speaking to (let's call it the master) has three signals:
CLOCK (2mhz at present)
SYNC
DATA IN
The clock runs continously and when the master wants to get some data it flips the sync line high for one clock cycle.
On the rising edge of the next clock cycle the master will expect to recieve the first bit of data (MSB first).
It will read in an entire byte and then ignore the DATA IN line until the next sync transition occurs.
I can draw a state diagram if that would help.
Quote: | The clock rate (for bits out per byte) can be done... but I don't see a continual 2 MHz, non-pausing stream as realistic. Did you expect to do anything else with this AVR besides provide a continual data stream of 2 Mbps? |
The only other thing i want the AVR to do is read the byte it is to send from one of the ports where DIP switches will be attached. To keep things simple the value on the port will be read at startup. If there is time, them it would be useful to read the port and have the new byte ready for the next sync pulse.
Essentially the AVR will behave like a parallel in - serial out shift register. |
|
Back to top |
|
|
DToolan
Joined: 14 Aug 2004 Posts: 1384 Location: Dallas / Fort Worth, Texas (USA)
|
Posted: Wed Oct 29, 2008 1:24 am Post subject: |
|
|
Code: | $regfile = "m8def.dat"
$crystal = 16000000
$hwstack = 32
$swstack = 32
$framesize = 40
CONFIG PORTB.4 = OUTPUT
' SPCR = &b01000000
' ^^^^^^^^
' ||||||||_ CLOCKRATE - of no consequence in slave mode since the AVR does not generate clock (clock is an input pin)
' ||||||___ PHASE - 0 = sample data-in on rising edge of clock, 1 = sample data-in on falling edge of clock
' |||||____ POLARITY - of no consequence in slave mode since the AVR does not generate clock (clock is an input pin)
' ||||_____ MASTER/SLV - 0 = SLAVE, 1 = MASTER
' |||______ DATA ORDER - 0 = transmit (data-out) MSB first, 1 = transmit (data-out) LSB first
' ||_______ SPI ENABLE - 0 = disabled, 1 = enabled
' |________ SPI INT EN - 0 = SPI interrupt disabled, 1 = SPI interrupt enabled
'MAIN - SS pin tied low
Wait4SyncHi:
SBIS PINB, 1 'test for sync flag high on PinB.1
JMP Wait4SyncHi 'no sync high
Read_Dip:
IN R24, PIND 'read dip switch on PinD
Fill_SPDR:
!OUT SPDR, R24 'fill SPDR
Wait4SyncLo:
SBIC PINB, 1 'test for sync flag low on PinB.1
JMP Wait4SyncLo 'no sync low
JMP Wait4SyncHi 'go back
END
'*************************************** |
|
|
Back to top |
|
|
|