Sida 1 av 4
SPI och DAC from the very början... *FUNGERAR*
Postat: 4 november 2005, 02:52:34
av JimmyAndersson
PIC: 18LF2320. DAC: TLV5618A. Läst databladen: Ja.
Har fått hem en DAC som *har* SPI (till skillnad från den andra jag provade..) Så nu ska det fungera bättre. Men efter några försök i MikroBasic så har jag insett att behöver lite hjälp.
Men först lite info:
I detta test tänkte jag skicka $FFF (alla 12 bitar satta) och $0 till DAC'en med en halv sekunds intervall. Detta för att enkelt se så att jag får ut rätt värde på A-utgången på DAC'en. (Mäter utgången med mätinstrument.)
PIC-kretsen kan max skicka ut 8 bitar och DAC'en kan ta emot 12 bitar. Med andra ord behöver jag skicka 8 bitar, kolla så de är skickade och sedan skicka resterande 3 bitar. Eller har jag missförstått något? I PIC'en finns "BF" (SSPSTAT-registret) men det används bara när man skickar data *till* PIC-kretsen. Jag hittar inte var jag läser av när alla 8 bitar är skickade....
Nu till mitt huvudsakliga problem:
I databladet för DAC'en står det att man skickar data till DAC'en så här:
1. CS (väljer A/B-utgång) ska vara låg *före* den första SCLK-signalen blir låg.
2. Det ska vara 16st låga SCLK innan CS blir hög. Under den tiden sänds datan.
Hur gör man detta på ett bra sätt? Jag har inte lyckats. Det går ju att göra med tok-extrem bitbanging som i detta exemplet:
PORTA.1 = 1 ' CS hög
PORTA.0 = 1 ' SCLK hög
PORTA.1 = 0 ' CS låg
KORT DELAY
PORTA.0 = 0 ' SCLK låg
PORTA.2... SKICKA FÖRSTA DATABITEN
PORTA.0 = 1 ' SCLK hög
KORT DELAY
PORTA.0 = 0 ' SCLK låg
PORTA.2... SKICKA ANDRA DATABITEN
PORTA.0 = 1 ' SCLK hög
osv tills allt är skickat. Men det skulle bli rena chock-koden.
Så: Hur löser jag det på ett snyggt sätt i MikroBasic? Jag ska senare använda båda kanalerna till ett projekt.
(Hoppas jag skrivit det ni behöver veta.)
edit: DAC'en har 12 databitar, inte 11 som jag skrev förrut..
Postat: 4 november 2005, 03:29:01
av EagleSpirit
Är du säker på att du bara skickar värdet på grejjerna? Kollade databladet och då ska ju adresser för vilken DAC du ska använda med i datat du skickar. Dvs, du ska skicka 16bit per "ändring". Läs på sidan 11 i databladet.
I microbasic skulle jag kunna tänka mig att det finns ett kommando som hjälper till med antingen SPI eller bitbanging. Men jag kan förklara på ett ungefär.
1. Lägga datat du vill skicka i två register (variablar). Med adressbitar på bit 15-12.
2. Starta en loop som går 8 gånger.
3. Skicka ut bit 7 i "högsta" registret du vill skicka.
4. Klocka SCLK
4. Rotera registret åt vänster.
5. Gör loopen tills den är klar
6. Gör om steg 2-5 med det "lägsta" registret du vill skicka.
Kom ihåg att setta och resetta CS-pinnen.
Hoppas den här förklaringen går att förstå? Det kanske är lättare att förstå om du läser databladet. Hur de två registrena ska se ut ser du i exemplena på sidan 11.
Just de, om du har möjlighet till större variablar än 8 bitar i microbasic kan du köra en loop som kör 16 gånger istället på en gång. Det blir ännu smidigare.
Om PICen har SPI möjligheter så skickar du två byte, alltså två gånger med olika data. Det är väldigt smidigt för då behöver du bara skriva ett par rader kod och sen sköter PICen resten.
Postat: 4 november 2005, 05:18:21
av JimmyAndersson
Tack! Hade helt missat sid11. Måste varit för snabb när jag bläddrade, för sidan innan och efter har jag läst.
Den förklarade en hel del. Jag undrade varför det ska vara 16st SCLK när den skickar 12bitar...
Nu är jag betydligt klokare.
Ska bara sova först, sedan ska jag testa.
Tack igen!

Postat: 4 november 2005, 12:35:23
av sodjan
> I PIC'en finns "BF" (SSPSTAT-registret) men det används bara när man skickar data *till* PIC-kretsen. Jag hittar inte var jag läser av när alla 8 bitar är skickade....
SPI modulen kommer *alltid* att skicka och ta emot samtidigt. Ävenom du inte "behöver" datat som har lästs in. BF flaggan signalerar att 8 bitar har lästs in i mottagningsregistret, och alltså har även 8 bitar sänds ut. Även om du inte behöver det inlästa datat, så är det fortfarande BF flaggan som används.
Allt enligt vad som förklaras i "17.3.2 OPERATION" på sid 158.
Kolla vad MikroBasic har för stöd för MSSP modulen. Om direkt stöd saknas eller verkar klumpigt, så är det ju bara att manipulera registren direkt, det blir hur som helst mycket smidigare än att bitbanga signalerna direkt från Basic.
Postat: 4 november 2005, 17:31:15
av JimmyAndersson
Om man söker på MSSP i MikroBasic så kommer det upp I2C-library. Men om jag söker på SPI så kommer det upp just SPI-library. Tyvärr verkar MikroBasic ha snöat in på seriella LCD-exempel och står inget om CS-signalen.
Så nu använder jag registren direkt, det är mycket smidigare. Man har mer koll på exakt vad som händer...
edit: Forumulerade om näst sista meningen.
Postat: 4 november 2005, 18:32:46
av vfr
Jag får för mig att CS-signalen egentligen inte tillhör SPI-standarden, utan är påhängt i efterhand för att t.ex välja olika enheter att prata med. Kanske därför den intefinns om nämnd.
Postat: 4 november 2005, 21:34:08
av JimmyAndersson
I flera exempel på nätet så har jag sett att man sätter CS låg direkt innan man börjar skicka data och efteråt sätter man CS hög. Detta ska (enligt exemplen) fungera med SPI-library i MikroBasic.
edit:

Det är lite kul ibland... För en minut sedan så skrev jag här att det inte fungerade. Men så ändrade lite så att CS blir hög *innan* den blir låg, precis som det ska vara. Så nu fungerar det!
(TRIS-raderna med LCD efteråt är till för att jag har en display på de pinnarna. Vill ju inte att de ska vara ingångar...)
Kod: Markera allt
const CHIP_SELECT = 0
dim value as word
sub procedure Init
TRISB = 0 ' LCD
TRISC.1 = 0 ' LCD
TRISC.2 = 0 ' LCD
PORTB = 0 ' LCD
PORTC.1 = 0 ' LCD
PORTC.2 = 0 ' LCD
SPI_init
ClearBit(TRISC,CHIP_SELECT) ' Utgång på ChipSelect (RC0)
TRISC.3=0 ' Utgång på SCK -Serial Clock- (RC3)
TRISC.5=0 ' Utgång på SDO -Data UT- (RC5)
end sub
sub procedure DAC_Output(dim value as word)
dim temp as byte
ClearBit(PORTC,CHIP_SELECT) ' Redo att skicka data...
temp = hi(value) ' Förbered bit 15-8
SPI_Write(temp) ' Skicka bit 15-8
temp = lo(value) ' Förbered bit 7-0
SPI_Write(temp) ' Skicka bit 7-0
SetBit(PORTC,CHIP_SELECT) ' Skickat klart...
end sub
main:
init
while true
value = %1100000000000000
DAC_Output(value) 'Skickar
delay_ms(500)
value = %1100111111111111
DAC_Output(value) 'Skickar
delay_ms(500)
wend
end.
Ganska smidig kod. Jag kunde förstås ha satt värdet direkt till "DAC_Output" men value-raden över finns där för att underlätta när jag bygger ut koden.
Postat: 4 november 2005, 22:26:42
av sodjan
Trevligt !
Jag antar att SPI_Write har en funktion för att vänta på föregående sändning. D.v.s vänta på BF flaggan. Annars skulle du väll behöva göra det själv i din kod...
Postat: 4 november 2005, 23:03:04
av JimmyAndersson
MikroBasics beskrivning av SPI_Write: "Writes byte data to SSPBUF, and immediately starts the transmission". Så den verkar fixa det själv.
En liten märklig sak har jag däremot upptäckt: Jag kopplade en lysdiod (plus motstånd) till DAC-utgången. Den ska ju vara tänd i 500ms för att sedan vara släckt i 500ms osv. Det är istället ca 7 sekunder innan den byter mellan tänd/släckt.
Ska prova att använda PIC-kretsens egna register direkt istället för MikroBasics SPI-library. Kanske flyter det bättre då.
Lite smidigt när man har en LCD-display som man kan skicka ut data på när man letar felkällor...

Postat: 5 november 2005, 00:13:23
av sodjan
Jo, men andra gånger måste man ju kolla att första sändningen är klar, annars bir det väll kajko i registren, antar jag...
Hm, det där med 7 sekunder verkar konstigt. Prova med att lägga antingen en kort delay (tillräckligt lång för att hinna sända 8 bitar med den SPI hastighet som du kör) *mellan* dina två SPI_Write, eller en koll på BF-flaggan. Det är möjligt att SPI_Write inte själv har full koll...
Jag brukar koppla på 2-3 vanliga LEDs på några oanvända pinnar och lägga ut "mönster" på dom som visar var i koden processorn befinner sig.
Postat: 5 november 2005, 01:28:31
av JimmyAndersson
Kollade BF-flaggan och lät en LED visa om den var satt eller inte. Resultat: Föregående sändning blir aldrig klar. (Nu blir inte DAC-utgången 5v som tidigare. Lysdioden lyser aldrig. Väntade 20-30sek.)
I databladet för DAC'en står det att den 14:e biten styr "Speed control".
1 = fast mode, 0 = slow mode. Jag har däremot inte hittat vad dessa olika lägen innebär lite mer exakt. Har däremot provat båda utan skillnad i resultat.
(I PIC'en har jag testat "Master clock=Fosc/4" och "Master clock=Fosc/16" som hastighet för sändningarna.)
Så här gjorde jag BF-kollen med lysdioderna förresten: (Resten av koden är samma som tidigare.)
Kod: Markera allt
sub procedure DAC_Output(dim value as word)
dim temp as byte
ClearBit(PORTC,CHIP_SELECT) ' Redo att skicka data...
temp = hi(value) ' Förbered bit 15-8
SPI_Write(temp) ' Skicka bit 15-8
kolla:
PORTA.0 = 1 'STATUS-LED 0
if SSPSTAT.0 = 1 then
PORTA.1 = 1 'STATUS-LED 1
temp = lo(value) ' Förbered bit 7-0
SPI_Write(temp) ' Skicka bit 7-0
SetBit(PORTC,CHIP_SELECT) ' Skickat klart...
else
PORTA.2 = 1 'STATUS-LED 2
goto kolla
end if
PORTA.0 = 0
PORTA.1 = 0
PORTA.2 = 0
end sub
Dvs:
1. Skicka bit 15-8.
2. Gå in i "kollen" och markera detta genom att tända LED 0.
3. Om inte BF är satt så tänd LED 2 och så gör vi en ny "koll" igen....
4. Om BF är satt så tänd LED 1 och gå vidare med att sätta bit 7-0.
5. Om allt går bra så släcks lysdioderna.
(BF kollas inte efter att bit 7-0 har skickats.)
Om inte BF är satt efter att ha skickat bit 15-8 så hamnar den i en loop. Tycker man borde kunna göra något nyttigare där.

Det jag kommer på är att skicka bit 15-8 igen, men det ska ju räcka med att skicka dem *en* gång... Hm. Någon idé?
edit: Plockar jag bort IF-raden och kör med koden som den var innan så fungerar det. (Var tvungen att kolla det igen, så att jag inte ändrat något annat...)
I nästa inlägg provar jag utan MikroBasic's SPI-funktioner.
Postat: 5 november 2005, 02:11:37
av JimmyAndersson
Provade att "prata" direkt med registren i PIC-kretsen. Resultat: Inga test-LED's lös. BF blir nöjd men det händer inget på DAC-utgången.
Så här ser koden ut iallafall:
Kod: Markera allt
const CHIP_SELECT = 0
dim value as word
sub procedure Init
TRISA = 0 'TESTLED
PORTA.0 = 0 'TESTLED
PORTA.1 = 0 'TESTLED
PORTA.2 = 0 'TESTLED
TRISB = 0 ' LCD
TRISC.1 = 0 ' LCD
TRISC.2 = 0 ' LCD
PORTB = 0 ' LCD
PORTC.1 = 0 ' LCD
PORTC.2 = 0 ' LCD
ClearBit(TRISC,CHIP_SELECT) ' Utgång på ChipSelect (RC0)
TRISC.3=0 ' Utgång på SCK -Serial Clock- (RC3)
TRISC.5=0 ' Utgång på SDO -Data UT- (RC5)
'Initierar SPI i 18LF2320. "Samma" inställningar som MikroBasic's SPI-library.
SSPSTAT.7=0 ' Input data sampled at the middle of data output time.
SSPSTAT.6=1 ' Data tas emot on rising edge of SCK
SSPCON1.7=0 ' Ingen WriteCollisionDetect
SSPCON1.6=0 ' Ingen ReceiveOverflowIndicator
SSPCON1.5=1 ' Enable serieport och SCK, SDo, SDI och SS
SSPCON1.4=0 ' CKP. Idle state for clock is a low level
SSPCON1.3=0 ' Master mode, clock = Fosc/4
SSPCON1.2=0 ' Master mode, clock = Fosc/4
SSPCON1.1=0 ' Master mode, clock = Fosc/4
SSPCON1.0=0 ' Master mode, clock = Fosc/4
end sub
sub procedure DAC_Output(dim value as word)
dim temp as byte
ClearBit(PORTC,CHIP_SELECT) ' Redo att skicka data...
temp = hi(value) ' Förbered bit 15-8
SSPBUF = temp ' Skicka bit 15-8
kolla:
PORTA.0 = 1 'STATUS-LED 0
if SSPSTAT.0 = 1 then
PORTA.1 = 1 'STATUS-LED 1
temp = lo(value) ' Förbered bit 7-0
SSPBUF = temp ' Skicka bit 7-0
SetBit(PORTC,CHIP_SELECT) ' Skickat klart...
else
PORTA.2 = 1 'STATUS-LED 2
goto kolla
end if
PORTA.0 = 0
PORTA.1 = 0
PORTA.2 = 0
end sub
main:
init
while true
value = %1100000000000000
DAC_Output(value) 'Skickar
delay_ms(500)
value = %1100111111111111
DAC_Output(value) 'Skickar
delay_ms(500)
wend
end.
Det kvittar vilket av exemplen jag får hjälp med. (Jag testar med båda två med andra ord.) Min BF-koll ser väl ok ut?
Postat: 5 november 2005, 20:23:50
av sodjan
Först en detalj som jag tror har varit uppe tidigare i en annan tråd...
Har inte de olika bitarna i registren *namn* i MikroBasic ????
T.ex så borde "SSPSTAT.0" skrivas "SSPSTAT.BF".
Detsamma gäller SSPCON1. Dels gör det betydligt enklare att
läsa din kod om du använder symbolerna, dels är det mindre
risk att du får buggar i koden.
Sen, kollen av BF flaggan blir lite snyggare och enklare att läsa med en while loop än if/else/goto/endif.
I sista exempelt så sätter du ju alla LEDs = 0 sist, d.v.s att om allt fungerar som det skall, så hinner du inte se att de blinkar till !
SSPBUF = temp ' Skicka bit 7-0
SetBit(PORTC,CHIP_SELECT) ' Skickat klart...
Skickat klart ? Hur vet du att det är "skickat klart" ???
Om inte MikroBasic är *mycket* långsamt, vill säga...
Postat: 5 november 2005, 20:41:47
av JimmyAndersson
Ska rätta till koden (med symbolerna istället) så det blir lättare att följa.
Det här med "skickat klart"... Jag visste inte riktigt vad jag skulle kalla den raden, därför blev det så. Men du har ju helt rätt: Jag vet ju inte att den faktiskt har skickat klart!
Ska göra en BF-koll där också. (Med "while" istället.)
-I'll be back!

Postat: 5 november 2005, 21:46:18
av bengt-re
CS har väl ändå inget med SPI att göra egentligen? Du kan ju ha flera olika CS på helt valfria ben eller tilloch med styrda av annan hårdvara. Bara att lösa CS som man själv vill..