
SPI och DAC from the very början... *FUNGERAR*
- JimmyAndersson
- Inlägg: 26578
- Blev medlem: 6 augusti 2005, 21:23:33
- Ort: Oskarshamn (En bit utanför)
- Kontakt:
bengt-re: Innan DAC'en kan ta emot data från SPI-överföringen så måste CS bli låg. Så trots att CS inte ingår i SPI så är det ju en "pinne" som måste sättas/cleras på rätt ställe när man ska sända data för att denna DAC över huvudtaget ska kunna prata via SPI.
sodjan: Hm... jag har inte "stängt av" CS mitt i överföringen. Inte medvetet iallafall. Jag clearar CS innan jag börjar skicka bit 15-8 till buffern. När bit 7-0 är skickade till buffern så sätter jag CS-biten igen. Allt enligt DAC'ens datablad (sid 6 "Figure 1"). -Jag ändrar med andra ord inte CS mitt i en överföring, bara innan och efter. Men:
Nu baserar jag detta på den koden som jag skrivit här. Med andra ord har jag inget som säger att all data verkligen skickas korrekt innan jag sätter CS-biten hög. (Det kan visserligen vara det du menar..)
Ska precis fixa till koden med BF-koll nu.
sodjan: Hm... jag har inte "stängt av" CS mitt i överföringen. Inte medvetet iallafall. Jag clearar CS innan jag börjar skicka bit 15-8 till buffern. När bit 7-0 är skickade till buffern så sätter jag CS-biten igen. Allt enligt DAC'ens datablad (sid 6 "Figure 1"). -Jag ändrar med andra ord inte CS mitt i en överföring, bara innan och efter. Men:
Nu baserar jag detta på den koden som jag skrivit här. Med andra ord har jag inget som säger att all data verkligen skickas korrekt innan jag sätter CS-biten hög. (Det kan visserligen vara det du menar..)

> När bit 7-0 är skickade till buffern så sätter jag CS-biten igen.
Precis !!! Det är antagligen där du gör fel !.
Du sätter CS innan alla 8 bitarna har hunnit sändas till DAC'en.
Att du skriver till registret/bufferten i PICen betyder ju inte att de *samtidigt* finns i DAC'en.
> Jag ändrar med andra ord inte CS mitt i en överföring...
Och jag tror att du gör det...
Precis !!! Det är antagligen där du gör fel !.
Du sätter CS innan alla 8 bitarna har hunnit sändas till DAC'en.
Att du skriver till registret/bufferten i PICen betyder ju inte att de *samtidigt* finns i DAC'en.
> Jag ändrar med andra ord inte CS mitt i en överföring...
Och jag tror att du gör det...
- JimmyAndersson
- Inlägg: 26578
- Blev medlem: 6 augusti 2005, 21:23:33
- Ort: Oskarshamn (En bit utanför)
- Kontakt:
...och jag är rädd för att du har rätt.
edit: Ok, ändringarna är gjorda. Det som mina "Status-LEDs" visar är att BF inte blir 1 efter att ha skickat bit 15-8 till buffern. Det märkliga är att BF blir inte 0 heller. Det kräver nog sin förklaring:
Det kvittar om jag sätter att en Status-LED ska lysa while SSPSTAT.BF = 0 eller om den ska lysa while SSPSTAT.BF = 1 -Den lyser nämligen hela tiden....
En annan konstig sak: StatusLED3 lyser aldrig. (Det är inget som är trasigt, har kollat det genom att byta plats på PORTA.3 och PORTA.0 i koden.)
Så här ser koden ut nu iallafall:
Liten förklaring av StatusLED:
LED 3 : Tänd = när man går in i "DAC_Output"-proceduren.
LED 0 : Tänd = Buffern är tom. (efter att bit 15-8 är skickade till buffern...)
LED 1 : Tänd = Buffern är full. *hick...*
LED 2 : Tänd = Buffern är tom. (efter att bit 7-0 är skickade till buffern...)
Har jag missuppfattat något angående BF? SPI skickar och tar emot data samtidigt, men ändå står det mest om hur man gör för att ta emot data i databladet. T.ex "if the SPI is only going to receive, the SDO output could be disabled (programmed as an input)."
Gäller det även för SDI? Det står inte.
I databladet (sid 158) står det även: "Buffer Full bit, BF (SSPSTAT<0>), indicates when SSPBUF has been loaded with the received data (transmission is complete). When the SSPBUF is read, the BF bit is cleared. This data may be irrelevant if the SPI is only a transmitter."
Men ändå kan man läsa av BF när man bara vill sända data till DAC'en?
Blir BF 0 även då?
Kikar man på sid156 om BF's statusbitar så står det:
"1 = Receive complete, SSPBUF is full
0 = Receive not complete, SSPBUF is empty"
Det tolkar jag som att BF ska bli 1 när allt är ok.
SSPBUF ska alltså bli full om jag skickat 8bitar till den? (I raden SSPBUF = temp.) Då blir det lite kortis i mitt huvud... Om programmet skickar 8bitar till SSPBUF, Blir BF 0 eller 1 när allt är "som det ska" ?
(Hoppas du hänger med på vad jag menar med "när allt är ok" och "när allt är som det ska"... Det är nästan lättare att skriva på engelska vad jag menar: "When data has successfully been written to SSPBUF"

edit: Ok, ändringarna är gjorda. Det som mina "Status-LEDs" visar är att BF inte blir 1 efter att ha skickat bit 15-8 till buffern. Det märkliga är att BF blir inte 0 heller. Det kräver nog sin förklaring:

En annan konstig sak: StatusLED3 lyser aldrig. (Det är inget som är trasigt, har kollat det genom att byta plats på PORTA.3 och PORTA.0 i koden.)
Så här ser koden ut nu 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
PORTA.3 = 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)
' TRISC.4=0 ' Genom att göra SDI till en utgång så disablas ingången. (Sid 160 i databladet.)
'Initierar DAC-kretsen (TLV 5618A) --------------
SSPSTAT.SMP=0 ' Input data sampled at the middle of data output time.
SSPSTAT.CKE=1 ' Data tas emot on rising edge of SCK
SSPCON1.WCOL=0 ' Ingen WriteCollisionDetect
SSPCON1.SSPOV=0 ' Ingen ReceiveOverflowIndicator
SSPCON1.SSPEN=1 ' Enable serieport och SCK, SDo, SDI och SS
SSPCON1.CKP=0 ' CKP. Idle state for clock is a low level
SSPCON1.SSPM3=0 ' Master mode, clock = Fosc/4
SSPCON1.SSPM2=0 ' Master mode, clock = Fosc/4
SSPCON1.SSPM1=0 ' Master mode, clock = Fosc/4
SSPCON1.SSPM0=0 ' Master mode, clock = Fosc/4
end sub
sub procedure DAC_Output(dim value as word)
dim temp as byte
PORTA.3 = 1 'STATUS-LED 3
ClearBit(PORTC,CHIP_SELECT) ' Redo att skicka data...
temp = hi(value) ' Förbered bit 15-8
SSPBUF = temp ' Skicka bit 15-8
while SSPSTAT.BF = 0
PORTA.0 = 1 'STATUS-LED 0
wend
PORTA.1 = 1 'STATUS-LED 1
temp = lo(value) ' Förbered bit 7-0
SSPBUF = temp ' Skicka bit 7-0
while SSPSTAT.BF = 0
PORTA.2 = 1 'STATUS-LED 2
wend
SetBit(PORTC,CHIP_SELECT) ' Här ska överföringen vara klar...
delay_ms(300) 'För att hinna se lysdioderna tända, när allt är ok.
PORTA.0 = 0
PORTA.1 = 0
PORTA.2 = 0
PORTA.3 = 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.
Liten förklaring av StatusLED:
LED 3 : Tänd = när man går in i "DAC_Output"-proceduren.
LED 0 : Tänd = Buffern är tom. (efter att bit 15-8 är skickade till buffern...)
LED 1 : Tänd = Buffern är full. *hick...*
LED 2 : Tänd = Buffern är tom. (efter att bit 7-0 är skickade till buffern...)
Har jag missuppfattat något angående BF? SPI skickar och tar emot data samtidigt, men ändå står det mest om hur man gör för att ta emot data i databladet. T.ex "if the SPI is only going to receive, the SDO output could be disabled (programmed as an input)."
Gäller det även för SDI? Det står inte.
I databladet (sid 158) står det även: "Buffer Full bit, BF (SSPSTAT<0>), indicates when SSPBUF has been loaded with the received data (transmission is complete). When the SSPBUF is read, the BF bit is cleared. This data may be irrelevant if the SPI is only a transmitter."
Men ändå kan man läsa av BF när man bara vill sända data till DAC'en?
Blir BF 0 även då?
Kikar man på sid156 om BF's statusbitar så står det:
"1 = Receive complete, SSPBUF is full
0 = Receive not complete, SSPBUF is empty"
Det tolkar jag som att BF ska bli 1 när allt är ok.
SSPBUF ska alltså bli full om jag skickat 8bitar till den? (I raden SSPBUF = temp.) Då blir det lite kortis i mitt huvud... Om programmet skickar 8bitar till SSPBUF, Blir BF 0 eller 1 när allt är "som det ska" ?
(Hoppas du hänger med på vad jag menar med "när allt är ok" och "när allt är som det ska"... Det är nästan lättare att skriva på engelska vad jag menar: "When data has successfully been written to SSPBUF"

- JimmyAndersson
- Inlägg: 26578
- Blev medlem: 6 augusti 2005, 21:23:33
- Ort: Oskarshamn (En bit utanför)
- Kontakt:
Har gjort lite mer felsökningar och upptäckte en sak:
'Status-LED 3' ska tändas när den går in i DAC_Output-proceduren. Den ska inte släckas förrän programmet går ur den proceduren. När man startar programmet på PIC'en så ser man aldrig att 'Status-LED 3' är tänd.
Så jag gjorde en test (med ett delay som jag flyttade rad för rad) för att se på vilken rad som gjorde att 'Status-LED 3' slockade. Resultat:
När PIC'en kommer till PORTA.0 = 1 'STATUS-LED 0 så slocknar lysdioden på PORTA.3 ! Märkligt.
Efter en helt ny kodtest och en koll i databladet så trillade poletten ner: Några av PORTA var analoga ingångar, så när jag lade till raden ADCON1 = %00001111 (dvs PORTA3 till 0 blir digitala) så fungerar det som det ska.
Fråga: Om jag inte lägger till ADCON1-raden, Varför kan de bara vara tända en och en när jag kör med "PORTA.x = 1" och "SetBit(PORTA, x)" ?
Någon som vet?
Det känns förresten riktigt bra när man lyckas lösa ett problem som till en början verkar totalkonstigt.
* * *
Nu över till orginal-problemet igen: 'StatusLED 0' indikerar att BF = 0 efter sändningen av bit 15-8.
Jag har fastnat lite... Om ni orkar kika på inlägget så var/är jag tveksam över om BF ska bli 1 eller 0 när det är som det ska (dvs när buffern skickat data till DAC'en.)
Jag har läst databladet (jepp!), men som jag skrivit i förra inlägget så förstår jag inte när BF blir 0 respektive 1. Se förra inlägget för mer info om hur jag menar.
En annan knepig grejj är att oavsett om jag (i BF-kollen) väljer att while-loopen ska gå igång (och tända StatusLED 0) om BF = 1, eller om den ska gå igång om BF = 0 så tänds den iallafall! Jag hänger inte med på varför...
Jag vet, jag har en del problem med denna kod. Men om man inte frågar så får man inte veta...
'Status-LED 3' ska tändas när den går in i DAC_Output-proceduren. Den ska inte släckas förrän programmet går ur den proceduren. När man startar programmet på PIC'en så ser man aldrig att 'Status-LED 3' är tänd.
Så jag gjorde en test (med ett delay som jag flyttade rad för rad) för att se på vilken rad som gjorde att 'Status-LED 3' slockade. Resultat:
När PIC'en kommer till PORTA.0 = 1 'STATUS-LED 0 så slocknar lysdioden på PORTA.3 ! Märkligt.
Efter en helt ny kodtest och en koll i databladet så trillade poletten ner: Några av PORTA var analoga ingångar, så när jag lade till raden ADCON1 = %00001111 (dvs PORTA3 till 0 blir digitala) så fungerar det som det ska.
Fråga: Om jag inte lägger till ADCON1-raden, Varför kan de bara vara tända en och en när jag kör med "PORTA.x = 1" och "SetBit(PORTA, x)" ?
Någon som vet?
Det känns förresten riktigt bra när man lyckas lösa ett problem som till en början verkar totalkonstigt.
* * *
Nu över till orginal-problemet igen: 'StatusLED 0' indikerar att BF = 0 efter sändningen av bit 15-8.
Jag har fastnat lite... Om ni orkar kika på inlägget så var/är jag tveksam över om BF ska bli 1 eller 0 när det är som det ska (dvs när buffern skickat data till DAC'en.)
Jag har läst databladet (jepp!), men som jag skrivit i förra inlägget så förstår jag inte när BF blir 0 respektive 1. Se förra inlägget för mer info om hur jag menar.
En annan knepig grejj är att oavsett om jag (i BF-kollen) väljer att while-loopen ska gå igång (och tända StatusLED 0) om BF = 1, eller om den ska gå igång om BF = 0 så tänds den iallafall! Jag hänger inte med på varför...

Jag vet, jag har en del problem med denna kod. Men om man inte frågar så får man inte veta...
Mycket text och jag har väll inte tänkt igenom allt till 100% men... 
Du bör nog göra en "dummy-läsning" av in-bufferten för att cleara BF flaggan.
Som databladet säger, så behöver du ju inte använda det lästa värdet till något. Att du inte "tömmer" bufferten är antagligen anledningen till att det verkar fungera *en* gång (sedan clearas aldrig BF flaggan mer).
Notera att SSPBUF har dubbla funktioner, man skriver det som skall skickas dit, och (efter utbyte av 8 bitar) så finns det lästa datat där (som du måste läsa men inte använda om du int behöver det).
Detta är en av de stora skillnaderna mellan SPI och I2C, SPI utbyter alltid data i båda riktiningar *samtidigt*, I2C alltid i en riktning *i taget*.
Så om vi börjar från ett noll-läge :
1. Skriv första byten till SSPBUF
2. Vänta på BF-flaggan (första byten är skickad och en är mottagen).
3. Läs SSPBUF (för att nollställa BF flaggan).
4. Skriv andra byten till SSPBUF.
5. Vänta på BF-flaggan (andra byten är skickad och en är mottagen).
6. Läs SSPBUF (för att nollställa BF flaggan och förbereda för nästa loop).
> ADCON1 = %00001111 (dvs PORTA3 till 0 blir digitala)
Standard åtgärd på alla PIC med analoga ingångar...

Du bör nog göra en "dummy-läsning" av in-bufferten för att cleara BF flaggan.
Som databladet säger, så behöver du ju inte använda det lästa värdet till något. Att du inte "tömmer" bufferten är antagligen anledningen till att det verkar fungera *en* gång (sedan clearas aldrig BF flaggan mer).
Notera att SSPBUF har dubbla funktioner, man skriver det som skall skickas dit, och (efter utbyte av 8 bitar) så finns det lästa datat där (som du måste läsa men inte använda om du int behöver det).
Detta är en av de stora skillnaderna mellan SPI och I2C, SPI utbyter alltid data i båda riktiningar *samtidigt*, I2C alltid i en riktning *i taget*.
Så om vi börjar från ett noll-läge :
1. Skriv första byten till SSPBUF
2. Vänta på BF-flaggan (första byten är skickad och en är mottagen).
3. Läs SSPBUF (för att nollställa BF flaggan).
4. Skriv andra byten till SSPBUF.
5. Vänta på BF-flaggan (andra byten är skickad och en är mottagen).
6. Läs SSPBUF (för att nollställa BF flaggan och förbereda för nästa loop).
> ADCON1 = %00001111 (dvs PORTA3 till 0 blir digitala)
Standard åtgärd på alla PIC med analoga ingångar...

- JimmyAndersson
- Inlägg: 26578
- Blev medlem: 6 augusti 2005, 21:23:33
- Ort: Oskarshamn (En bit utanför)
- Kontakt:
Jo, jag skrev ganska mycket text, men du lyckades ändå svara på det jag behövde veta. 
Är rädd för att detta inlägg också innehåller mycket text...
Jag har inte lyckats få det att fungera ännu, men jag är på väg.
Tänkte bara kolla en grejj: Jag måste ju läsa av SSPBUF. SPI på PIC-kretsen skickar och tar emot 8 bitar i taget. Räcker det att läsa av en byte för att BF ska nollställas? -Funderade på detta eftersom jag skickar 16bitar totalt, (8 bitar i taget.) men SSPBUF lagrar ju bara en byte.
Jag följde din lista och ändrade min kod:
Jag lade till read = SSPBUF innan jag skickar bit 15-8. BF måste ju vara noll innan jag kan skicka ut något, men BF kanske redan är noll från början?
Tyvärr blir reslutatet precis som tidigare: BF blir aldrig '1' efter att jag skickat byte 15-8. Det som är lite konstigt är att ifall jag skriver while SSPSTAT.BF = 1 istället för while SSPSTAT.BF = 0 så går programmet ändå inte ur while....
Gör jag något fel? Troligen, det är ju sällan programmets fel att något inte fungerar...
Förresten: Om jag hade tagit emot data på SDI-pinnen (på PIC'en) så hade det ju hamnat i 'read'-variabeln ovan. Men nu är SDI inte ansluten till något (eftersom DACen bara kan ta emot data), så vad blir innehållet i 'read'? Bara nollor? -Bara lite nyfiken som vanligt...

Är rädd för att detta inlägg också innehåller mycket text...
Jag har inte lyckats få det att fungera ännu, men jag är på väg.
Tänkte bara kolla en grejj: Jag måste ju läsa av SSPBUF. SPI på PIC-kretsen skickar och tar emot 8 bitar i taget. Räcker det att läsa av en byte för att BF ska nollställas? -Funderade på detta eftersom jag skickar 16bitar totalt, (8 bitar i taget.) men SSPBUF lagrar ju bara en byte.
Jag följde din lista och ändrade min kod:
Jag lade till read = SSPBUF innan jag skickar bit 15-8. BF måste ju vara noll innan jag kan skicka ut något, men BF kanske redan är noll från början?
Kod: Markera allt
sub procedure DAC_Output(dim value as word)
dim temp as byte
dim read as byte
PORTA.3 = 1 'STATUS-LED 3
ClearBit(PORTC,CHIP_SELECT) ' Redo att skicka data...
read = SSPBUF ' Läs av innehållet. <---Är inte helt säker på att den raden behövs.
temp = hi(value) ' Förbered bit 15-8
SSPBUF = temp ' Skicka bit 15-8
while SSPSTAT.BF = 0 ' BF ska bli 1 när buffern fått temp-datan.
PORTA.0 = 1 'STATUS-LED 0
wend
PORTA.1 = 1 'STATUS-LED 1
read = SSPBUF ' Läs av innehållet. (Detta innehåll används inte.)
'Nu ska BF ha blivit noll igen och kan ta emot ny temp-data.
temp = lo(value) ' Förbered bit 7-0
SSPBUF = temp ' Skicka bit 7-0
while SSPSTAT.BF = 0 ' BF ska bli 1 när buffern fått temp-datan.
PORTA.2 = 1 'STATUS-LED 2
wend
read = SSPBUF ' Läs av innehållet. (Detta innehåll används inte.)
'Nu ska BF ha blivit noll igen och kan ta emot ny temp-data.
SetBit(PORTC,CHIP_SELECT) ' Skickat klart...
delay_ms(300) 'För att hinna se lysdioderna tända, när allt är ok.
PORTA.0 = 0
PORTA.1 = 0
PORTA.2 = 0
PORTA.3 = 0
end sub
Tyvärr blir reslutatet precis som tidigare: BF blir aldrig '1' efter att jag skickat byte 15-8. Det som är lite konstigt är att ifall jag skriver while SSPSTAT.BF = 1 istället för while SSPSTAT.BF = 0 så går programmet ändå inte ur while....
Gör jag något fel? Troligen, det är ju sällan programmets fel att något inte fungerar...

Förresten: Om jag hade tagit emot data på SDI-pinnen (på PIC'en) så hade det ju hamnat i 'read'-variabeln ovan. Men nu är SDI inte ansluten till något (eftersom DACen bara kan ta emot data), så vad blir innehållet i 'read'? Bara nollor? -Bara lite nyfiken som vanligt...

Du bör nog inte ha SDI "öppen", utan lägga den hög eller låg (via ett motstånd). "read" borde bli x'FF' eller x'00' beroende på hur du gjorde med SDI pinnen.
Och när det gäller 8 eller 16 bitar...
SPI enheten hanterar 8 bitar i taget. Det är allt den vet.
Att man sen kör 2 eller fler separata överföringar är en annan sak.
För övrigt vet jag inte.
Är du säker på att alla 4 dioderna kan tändas alls ?
Kanske lägga till :
PORTA.0 = 1
PORTA.1 = 1
PORTA.2 = 1
PORTA.3 = 1
delay_ms(300) 'För att hinna se lysdioderna tända, när allt är ok.
PORTA.0 = 0
PORTA.1 = 0
PORTA.2 = 0
PORTA.3 = 0
någonstans i början så att alla fyra dioderna tänds upp ett ögonblick...
Och när det gäller 8 eller 16 bitar...
SPI enheten hanterar 8 bitar i taget. Det är allt den vet.
Att man sen kör 2 eller fler separata överföringar är en annan sak.
För övrigt vet jag inte.
Är du säker på att alla 4 dioderna kan tändas alls ?
Kanske lägga till :
PORTA.0 = 1
PORTA.1 = 1
PORTA.2 = 1
PORTA.3 = 1
delay_ms(300) 'För att hinna se lysdioderna tända, när allt är ok.
PORTA.0 = 0
PORTA.1 = 0
PORTA.2 = 0
PORTA.3 = 0
någonstans i början så att alla fyra dioderna tänds upp ett ögonblick...
- JimmyAndersson
- Inlägg: 26578
- Blev medlem: 6 augusti 2005, 21:23:33
- Ort: Oskarshamn (En bit utanför)
- Kontakt:
Bra idé att tända lysdioderna i början också! Alla tänds, så där är det ok.
Dessvärre har jag inte fått resten att fungera ännu, trots massor av tester. (Det kanske inte ser ut som om jag testar så mycket, men jag har inte på långa vägar skrivit inlägg om alla ändringar jag gjort i koden. Mina inlägg blir tillräckligt långa ändå...)
Tyvärr är det svårt att hitta MikroBasic-exempel på nätet som inte innehåller deras egna librarys. -Jag vill ju kunna få det att fungera utan dem. Dels för att man lär sig mer och dels för att det blir lättare att bygga om koderna till andra programmeringsspråk.
Har kollat på asm-exempel för detta och vad jag har kunnat se i dem så har jag gjort på rätt sätt.
Nåväl, jag testar vidare. Förr eller senare så kommer det fungera.
edit: Satt och kollade på tv utan en tanke på programmering. Då plötsligt fick jag en
:
DAC'en vill ju ta emot alla 16 bitar i en jämn ström med samma hastighet som SCLK-pulsen. Men om programmet går in i en while-loop efter att ha skickat hälften, så blir ju dataströmmen till DAC'en avbruten!
Det är säkert därför som det fungerade (fast gick 14 gånger för sakta) när jag använde MikroBasic's libraryfunktioner *utan* while-loopen.
Frågan är bara hur jag ska lösa det utan att avbryta sändningen...
Hittade detta i databladet: "Generally, the MSSP interrupt is used to
determine when the transmission/reception has completed."
Det kanske kan vara värt att testa i detta fallet.
Interrupten SSPIF blir hög när en byte är mottagen. (Närmare bestämt när innehållet hamnar i SSPBUF vid en mottagning.)
Nu gäller det att komma på hur jag ska koda för att programmet inte ska stanna för länge någonstans...
Dessvärre har jag inte fått resten att fungera ännu, trots massor av tester. (Det kanske inte ser ut som om jag testar så mycket, men jag har inte på långa vägar skrivit inlägg om alla ändringar jag gjort i koden. Mina inlägg blir tillräckligt långa ändå...)

Tyvärr är det svårt att hitta MikroBasic-exempel på nätet som inte innehåller deras egna librarys. -Jag vill ju kunna få det att fungera utan dem. Dels för att man lär sig mer och dels för att det blir lättare att bygga om koderna till andra programmeringsspråk.
Har kollat på asm-exempel för detta och vad jag har kunnat se i dem så har jag gjort på rätt sätt.
Nåväl, jag testar vidare. Förr eller senare så kommer det fungera.
edit: Satt och kollade på tv utan en tanke på programmering. Då plötsligt fick jag en

DAC'en vill ju ta emot alla 16 bitar i en jämn ström med samma hastighet som SCLK-pulsen. Men om programmet går in i en while-loop efter att ha skickat hälften, så blir ju dataströmmen till DAC'en avbruten!
Det är säkert därför som det fungerade (fast gick 14 gånger för sakta) när jag använde MikroBasic's libraryfunktioner *utan* while-loopen.
Frågan är bara hur jag ska lösa det utan att avbryta sändningen...
Hittade detta i databladet: "Generally, the MSSP interrupt is used to
determine when the transmission/reception has completed."
Det kanske kan vara värt att testa i detta fallet.
Interrupten SSPIF blir hög när en byte är mottagen. (Närmare bestämt när innehållet hamnar i SSPBUF vid en mottagning.)
Nu gäller det att komma på hur jag ska koda för att programmet inte ska stanna för länge någonstans...
> DAC'en vill ju ta emot alla 16 bitar i en jämn ström med samma hastighet som SCLK-pulsen.
Vad menar du med "jämn ström" ?
Databladet har bara krav på min-tider för klockpulserna, inga max-tider.
> Men om programmet går in i en while-loop efter att ha skickat hälften,
Det gör det inte.
Programmet ligger i en while-loop *medans* första hälften skickas.
> så blir ju dataströmmen till DAC'en avbruten!
Bör inte vara något problem, så länge man inte fipplar med CS. Så vitt kjag kan se av databladet så är det OK med en paus mellan de två byten.
> Hittade detta i databladet: "Generally, the MSSP interrupt is used to
> determine when the transmission/reception has completed."
> Det kanske kan vara värt att testa i detta fallet.
Eller att polla BF flaggan som du gör nu. Ingen större skillnad.
> Nu gäller det att komma på hur jag ska koda för att programmet inte ska stanna för länge någonstans...
Kör assembler...
Ärligt talat, eftersom du redan hanterar de olika MSSP registren direkt, så är det ju inte så stor skillnad att skriva hela SPI överföringen som inline-asm. Resten kan ju ligga kvar i Basic.
Vad menar du med "jämn ström" ?
Databladet har bara krav på min-tider för klockpulserna, inga max-tider.
> Men om programmet går in i en while-loop efter att ha skickat hälften,
Det gör det inte.
Programmet ligger i en while-loop *medans* första hälften skickas.
> så blir ju dataströmmen till DAC'en avbruten!
Bör inte vara något problem, så länge man inte fipplar med CS. Så vitt kjag kan se av databladet så är det OK med en paus mellan de två byten.
> Hittade detta i databladet: "Generally, the MSSP interrupt is used to
> determine when the transmission/reception has completed."
> Det kanske kan vara värt att testa i detta fallet.
Eller att polla BF flaggan som du gör nu. Ingen större skillnad.
> Nu gäller det att komma på hur jag ska koda för att programmet inte ska stanna för länge någonstans...
Kör assembler...

Ärligt talat, eftersom du redan hanterar de olika MSSP registren direkt, så är det ju inte så stor skillnad att skriva hela SPI överföringen som inline-asm. Resten kan ju ligga kvar i Basic.
- JimmyAndersson
- Inlägg: 26578
- Blev medlem: 6 augusti 2005, 21:23:33
- Ort: Oskarshamn (En bit utanför)
- Kontakt:
Och jag som trodde jag hade hittat en lösning...
Det får nog nästan bli en inline-asm. Man kan ju alltid testa.
edit:
Har gjort ett inline-asm-test. Men när jag kör 'build' så får jag dessa felmeddelande:
0:0 0 Linker error: Invalid asm CTR0 EQU 0X20 0 dactest9.pbas
0:0 0 Linker error: Invalid asm DLY0 EQU 0X21 0 dactest9.pbas
0:0 0 Linker error: Invalid asm DLY1 EQU 0X22 0 dactest9.pbas
0:0 0 Linker error: Invalid asm #DEFINE CS 0X01 0 dactest9.pbas
Kan redan nu passa på att berätta att jag har glömt hur 'BANKSEL' och banker fungerar...
Jag gick efter en pdf-fil som heter "Getting started: SPI" från Microchip.
Jag måste förstås modifiera koden lite för att kunna skicka variabel-innehåll eftersom exemplet i pdf-filen var lite annorlunda. Men man ser iallafall hur man skickar/tar emot.
Detta är alltså min inline-assembler-del:
off topic: Jag har gjort så många kod-tester att jag har börjat trycka CTRL+S när jag ska spara ett inlägg...

Det får nog nästan bli en inline-asm. Man kan ju alltid testa.
edit:
Har gjort ett inline-asm-test. Men när jag kör 'build' så får jag dessa felmeddelande:
0:0 0 Linker error: Invalid asm CTR0 EQU 0X20 0 dactest9.pbas
0:0 0 Linker error: Invalid asm DLY0 EQU 0X21 0 dactest9.pbas
0:0 0 Linker error: Invalid asm DLY1 EQU 0X22 0 dactest9.pbas
0:0 0 Linker error: Invalid asm #DEFINE CS 0X01 0 dactest9.pbas
Kan redan nu passa på att berätta att jag har glömt hur 'BANKSEL' och banker fungerar...

Jag gick efter en pdf-fil som heter "Getting started: SPI" från Microchip.
Jag måste förstås modifiera koden lite för att kunna skicka variabel-innehåll eftersom exemplet i pdf-filen var lite annorlunda. Men man ser iallafall hur man skickar/tar emot.
Detta är alltså min inline-assembler-del:
Kod: Markera allt
asm
Ctr0 EQU 0x20 ; Counter variable - sent to SPI
Dly0 EQU 0x21 ; Delay Variable (low byte)
Dly1 EQU 0x22 ; Delay Variable (high byte)
#define CS 0x01 ; PORTC,1
Send_DT bcf PORTC,CS ; Enable Chip Select Output (low)
movf Ctr0,W ; Get Ctr (Counter Value) in W
movwf SSPBUF ; put in SSPBUF
BANKSEL SSPSTAT ; BANK 1
Char1 btfss SSPSTAT,BF ; Data transfer complete? (Buffer Full?)
goto Char1 ; if not, check again
BANKSEL SSPBUF ; BANK0
movf SSPBUF,W ; Get Data from SSPBUF
;
bsf PORTC,CS ; Disable Chip Select Output (high)
Update_Test_Counter
incf Ctr0,F ; Increment counter variable
Delay movlw 0x01 ; Simple Delay loop
movwf Dly1 ; |
movlw 0x0F ; |
movwf Dly0 ; |
DlyLoop decfsz Dly0,F ; |
goto DlyLoop ; |
decfsz Dly1,F ; |
goto DlyLoop ; |
; Done Delay ; \_/
DoAgain goto Send_DT ; Done, Send Next Byte.
end asm
off topic: Jag har gjort så många kod-tester att jag har börjat trycka CTRL+S när jag ska spara ett inlägg...

- EagleSpirit
- Inlägg: 1288
- Blev medlem: 27 maj 2003, 23:15:48
- Ort: Västerås
- Kontakt:
Det var jääätttemycket text i den här tråden och jag orkade tyvärr inte läsa igenom allt men här är den kod jag har använt när jag ska skicka data till en DAC (MAX541).
inti_SPI konfigurerar SPI porten och send_SPI skickar datat som finns i variablerna dac_h och dac_l. För att PICen inte ska börja skicka andra värdet innan första är klart har jag en delay på 100µs... detta skulle kunna lösas med:
Jag tror att den sista instruktionen (movf SSPBUF,w) behövs för att ta bort det data som porten tog emot vid överföringen... I det här fallet finns det ju inget där men jag tror den resettar en flagga nånstans.
delay100µs är en subrutin jag har så det får du lösa på något annat sätt och variablerna dac_l och dac_h får du såklart skapa själv.
Inställningarna i SSPSTAT och SSPCON1 registrena beror ju på hur du vill att grejjerna ska fungera. Det är bara att kolla databladet för PIC-kretsen.
PS. Jag har för mig att den här kodsnutten fungerade
Kod: Markera allt
spi_port EQU PORTC
tris_spi_port EQU TRISC
spi_sdo EQU 0x05
spi_sclk EQU 0x03
spi_cs EQU 0x01
init_spi:
movlw b'00000000' ;MSSP STATUS Register
movwf SSPSTAT
movlw b'00100001'
movwf SSPCON1
send_SPI:
bsf spi_port,spi_cs
movf dac_h,W
movwf SSPBUF
call delay100us
movf dac_l,W
movwf SSPBUF
bcf spi_port,spi_cs
call delay100us
Kod: Markera allt
btfss SSPSTAT,BF
goto $-2
movf SSPBUF,w
delay100µs är en subrutin jag har så det får du lösa på något annat sätt och variablerna dac_l och dac_h får du såklart skapa själv.
Inställningarna i SSPSTAT och SSPCON1 registrena beror ju på hur du vill att grejjerna ska fungera. Det är bara att kolla databladet för PIC-kretsen.
PS. Jag har för mig att den här kodsnutten fungerade

EagleSpirit, behöver du inte vänta på att byte-2 är sänd innan du sätter CS låg ? Betyder inte det att du avbryter mottagandet i DAC'en ?
> Jag tror att den sista instruktionen (movf SSPBUF,w) behövs för att ta bort
> det data som porten tog emot vid överföringen... I det här fallet finns
> det ju inget där men jag tror den resettar en flagga nånstans.
SPI tar *alltid* emot någonting, sen kanske man inte behöver datat, men det är en annan sak. Så det "finns" alltid något i SSPBUF, även om det alltid är x'FF' eller x'00' (beroende på hur man har kopplat datalinjen in till PICen.
En läsning av SSPBUF "nollar" BF (Buffer Full) flaggan, som ju används för att se att en sändning (och mottagning eftersom det sker samtidigt) är klar.
Jimmy, har du kollat kapitlet om inline-ASM och hur man kommer åt Basic variabler ? Det är tveksamt om inline-asm koden skall ha egna EQU, du använder väll normalt de symboler som Basic har definierat. Tyvärr är manualen ganska tunn kring detta, ser jag nu när jag kollar. Konstigt att de inte har med något ordentligt exemepl !
Ett par andra saker :
> BANKSEL SSPSTAT ; BANK 1
Alltså, man använder ju BANKSEL för att inte behöva bekymra sig om vilken bank ett register finns i. Alltså är kommenteren inte bara onödig, utan förtar själva syften med BANKSEL. Sen är det en annan fråga m BANKSEL stöds alls i inline-asm, BANKSEL är ett direktiv/macro i MPASM, och jag vet inte om MikroBasic använder sig av MPASM eller någon egen assembeker. Det står att man måste sätta rätt bank "manualy", vilket kan syfta på att köra BSF/BCF direkt på bank-bitarna.
Hur som helst...
EagleSpirit's exempel borde gå att få att fungera. Jag skulle nog lägga till check av BF efter sändning av båda byten innan man lägger CS låg (eller hög, minns inte hur det var med TI DACen) igen.
Ta bort dina EQU och kör mot Basic variablerna direkt, så får du se vad som händer.
> Jag tror att den sista instruktionen (movf SSPBUF,w) behövs för att ta bort
> det data som porten tog emot vid överföringen... I det här fallet finns
> det ju inget där men jag tror den resettar en flagga nånstans.
SPI tar *alltid* emot någonting, sen kanske man inte behöver datat, men det är en annan sak. Så det "finns" alltid något i SSPBUF, även om det alltid är x'FF' eller x'00' (beroende på hur man har kopplat datalinjen in till PICen.
En läsning av SSPBUF "nollar" BF (Buffer Full) flaggan, som ju används för att se att en sändning (och mottagning eftersom det sker samtidigt) är klar.
Jimmy, har du kollat kapitlet om inline-ASM och hur man kommer åt Basic variabler ? Det är tveksamt om inline-asm koden skall ha egna EQU, du använder väll normalt de symboler som Basic har definierat. Tyvärr är manualen ganska tunn kring detta, ser jag nu när jag kollar. Konstigt att de inte har med något ordentligt exemepl !
Ett par andra saker :
> BANKSEL SSPSTAT ; BANK 1
Alltså, man använder ju BANKSEL för att inte behöva bekymra sig om vilken bank ett register finns i. Alltså är kommenteren inte bara onödig, utan förtar själva syften med BANKSEL. Sen är det en annan fråga m BANKSEL stöds alls i inline-asm, BANKSEL är ett direktiv/macro i MPASM, och jag vet inte om MikroBasic använder sig av MPASM eller någon egen assembeker. Det står att man måste sätta rätt bank "manualy", vilket kan syfta på att köra BSF/BCF direkt på bank-bitarna.
Hur som helst...
EagleSpirit's exempel borde gå att få att fungera. Jag skulle nog lägga till check av BF efter sändning av båda byten innan man lägger CS låg (eller hög, minns inte hur det var med TI DACen) igen.
Ta bort dina EQU och kör mot Basic variablerna direkt, så får du se vad som händer.
- EagleSpirit
- Inlägg: 1288
- Blev medlem: 27 maj 2003, 23:15:48
- Ort: Västerås
- Kontakt:
sodjan: Ja jag vet att den alltid tar emot data, det har väl stått tidigare i tråden här nånstans? I alla fall, om man inte kollar BF-flaggan så behöver man ju heller inte resetta den, eller hur? BF-flaggan har liksom ingen funktion om man bara använder delay varianten.
Om man använder en check och man skriver till SSPBUF så kommer den skicka iväg grejjerna trots att BF redan är satt sen tidigare. Därför bör man läsa SSBUF för att inte nästa check ska bli fel.
Ojdå, missade det där med att man ska checka innan man togglar CS... hmm, undrar om det har varit orsaken till problem tidigare. Du har helt rätt...
Jag glömde dessutom skriva att checken av BF är istället för en delay på 100µs... dvs, det ska ske en check för varje byte som skickas..
Om man använder en check och man skriver till SSPBUF så kommer den skicka iväg grejjerna trots att BF redan är satt sen tidigare. Därför bör man läsa SSBUF för att inte nästa check ska bli fel.
Ojdå, missade det där med att man ska checka innan man togglar CS... hmm, undrar om det har varit orsaken till problem tidigare. Du har helt rätt...
Jag glömde dessutom skriva att checken av BF är istället för en delay på 100µs... dvs, det ska ske en check för varje byte som skickas..
- JimmyAndersson
- Inlägg: 26578
- Blev medlem: 6 augusti 2005, 21:23:33
- Ort: Oskarshamn (En bit utanför)
- Kontakt:
Tack för koden EagleSpirit!
Jag kom på att checken av BF är istället för delayen.
Har 'översatt' till MikroBasic nu. Så här ser hela skicka-proceduren ut:
Sedan har jag dessa rader globalt eftersom MikroBasic inte var så pigg på att ha det i en procedur:
Nu får jag bara två fel vid build:
0:0 0 Linker error: DAC_H: argument not found
0:0 0 Linker error: DAC_L: argument not found
Jag kom på att checken av BF är istället för delayen.

Har 'översatt' till MikroBasic nu. Så här ser hela skicka-proceduren ut:
Kod: Markera allt
sub procedure DAC_Output(dim value as word)
dim spi_sdo as byte
dim spi_sclk as byte
dim spi_cs as byte
dim dac_h as byte
dim dac_l as byte
spi_sdo = $5
spi_sclk = $3
spi_cs = $1
dac_h = hi(value) ' Förbered bit 15-8
dac_l = lo(value) ' Förbered bit 7-0
asm
bsf spi_port,spi_cs
movf dac_h,W 'skickar bit 15-8
movwf SSPBUF
btfss SSPSTAT,BF
goto $-2
movf SSPBUF,w
movf dac_l,W
movwf SSPBUF 'skickar bit 7-0
bcf spi_port,spi_cs
btfss SSPSTAT,BF
goto $-2
movf SSPBUF,w
end asm
end sub
Sedan har jag dessa rader globalt eftersom MikroBasic inte var så pigg på att ha det i en procedur:
Kod: Markera allt
symbol spi_port = PORTC ' Dvs, man kan skriva 'spi_port' istället för 'PORTC'
symbol tris_spi_port = TRISC
Nu får jag bara två fel vid build:
0:0 0 Linker error: DAC_H: argument not found
0:0 0 Linker error: DAC_L: argument not found