SPI och DAC from the very början... *FUNGERAR*

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
JimmyAndersson
Inlägg: 26578
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

SPI och DAC from the very början... *FUNGERAR*

Inlägg 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..
Senast redigerad av JimmyAndersson 17 november 2005, 18:22:33, redigerad totalt 2 gånger.
Användarvisningsbild
EagleSpirit
Inlägg: 1288
Blev medlem: 27 maj 2003, 23:15:48
Ort: Västerås
Kontakt:

Inlägg 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.
Användarvisningsbild
JimmyAndersson
Inlägg: 26578
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

Inlägg 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. :lol:

Den förklarade en hel del. Jag undrade varför det ska vara 16st SCLK när den skickar 12bitar... :roll:

Nu är jag betydligt klokare.
Ska bara sova först, sedan ska jag testa.

Tack igen! :)
Senast redigerad av JimmyAndersson 4 november 2005, 20:20:53, redigerad totalt 1 gång.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg 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.
Användarvisningsbild
JimmyAndersson
Inlägg: 26578
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

Inlägg 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.
Senast redigerad av JimmyAndersson 4 november 2005, 19:24:01, redigerad totalt 1 gång.
Användarvisningsbild
vfr
EF Sponsor
Inlägg: 3515
Blev medlem: 31 mars 2005, 17:55:45
Ort: Kungsbacka

Inlägg 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.
Användarvisningsbild
JimmyAndersson
Inlägg: 26578
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

Inlägg 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: :lol: 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.
Senast redigerad av JimmyAndersson 7 november 2005, 03:21:23, redigerad totalt 1 gång.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg 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...
Användarvisningsbild
JimmyAndersson
Inlägg: 26578
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

Inlägg 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... :)
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg 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.
Användarvisningsbild
JimmyAndersson
Inlägg: 26578
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

Inlägg 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.
Senast redigerad av JimmyAndersson 5 november 2005, 03:44:01, redigerad totalt 2 gånger.
Användarvisningsbild
JimmyAndersson
Inlägg: 26578
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

Inlägg 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?
Senast redigerad av JimmyAndersson 7 november 2005, 03:22:43, redigerad totalt 1 gång.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg 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...
Användarvisningsbild
JimmyAndersson
Inlägg: 26578
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

Inlägg 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! 8)
Användarvisningsbild
bengt-re
EF Sponsor
Inlägg: 4829
Blev medlem: 4 april 2005, 16:18:59
Skype: bengt-re
Ort: Söder om söder
Kontakt:

Inlägg 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..
Skriv svar