SPI och DAC from the very början... *FUNGERAR*
Jag var bara tvungen att slänga upp en 18F2220 och en TLV5618 på en labbplatta... 
Koden nedan fungerar. Den ger en sågtandsspänning på kanal A med en period på ca 0.5 sek. Spännings ref är en LM385BZ-1.2, alltså 1.2 V och topspännngen på utsignalen blir alltså ca 2.4 V. CS sitter på PORTB.0 och SDO, SCK är de vanliga. Om jag ändrar till "OSC = HSPLL", blir perioden ca 0.12 sek som förväntat. Obs, det är ätt "ful-hack" bara för att få igång något med mer hårdkodade sakar än vad man normalt vill ha...

Koden nedan fungerar. Den ger en sågtandsspänning på kanal A med en period på ca 0.5 sek. Spännings ref är en LM385BZ-1.2, alltså 1.2 V och topspännngen på utsignalen blir alltså ca 2.4 V. CS sitter på PORTB.0 och SDO, SCK är de vanliga. Om jag ändrar till "OSC = HSPLL", blir perioden ca 0.12 sek som förväntat. Obs, det är ätt "ful-hack" bara för att få igång något med mer hårdkodade sakar än vad man normalt vill ha...
Kod: Markera allt
;**********************************************************
list p=18f2220
include "p18f2220.inc"
;**********************************************************
; CONFIG settings
;
config OSC = HS, FSCM=OFF, IESO=OFF, PWRT = ON, BOR = OFF
config WDT = OFF, MCLRE=OFF, STVR = OFF, LVP = OFF
config DEBUG = OFF, CP0 = OFF, CP1 = OFF
config CPB = OFF, CPD = OFF, WRT0 = OFF
config WRT1 = OFF, WRTB = OFF
config WRTC = OFF, WRTD = OFF, EBTR0 = OFF, EBTR1 = OFF
config EBTRB = OFF
;
;**********************************************************
; Variables. We put them in the access bank...
;
vars UDATA_ACS
dac_h RES 1
dac_l RES 1
;**********************************************************
Boot CODE h'0000'
goto Start
;**********************************************************
Main CODE
Start
bcf trisc, 3 ; Quick-n-dirty TRIS bits...
bcf trisc, 5
bcf trisb, 0
bcf trisb, 1
clrf dac_l ; Init DAC value.
clrf dac_h
bsf dac_h, 7 ; Update DAC cannel A.
movlw b'00000000' ; Setup of MSSP/SPI
movwf SSPSTAT
movlw b'00100010'
movwf SSPCON1
loop
clrf wreg ; Increment DAC value.
incf dac_l, f
addwfc dac_h, f
btfss dac_h,4 ; Over max value ?
bra send2spi ; No, go update DAC
clrf dac_l ; Yes, re-init value.
clrf dac_h
bsf dac_h, 7
send2spi
bcf portb,0 ; Enable CS
movff dac_h, SSPBUF ; First byte
first_byte_wait
btfss SSPSTAT, BF ; Wait for BF flag.
bra first_byte_wait
movf SSPBUF, W ; Dummy read...
movff dac_l, SSPBUF ; Second byte
sec_byte_wait
btfss SSPSTAT, BF ; Wait for BF flag.
bra sec_byte_wait
movf SSPBUF, W ; Dummy read...
bsf portb,0 ; Disable CS
goto loop ; Once again...
end
- JimmyAndersson
- Inlägg: 26578
- Blev medlem: 6 augusti 2005, 21:23:33
- Ort: Oskarshamn (En bit utanför)
- Kontakt:
Tack för koden!!
Jag har haft mycket att göra, men nu är jag tillbaka.
Hm, fick några felmeddelande när jag körde 'build'.
Error[113] DACTEST11.ASM 32 : Symbol not previously defined (trisc)
Error[113] DACTEST11.ASM 33 : Symbol not previously defined (trisc)
Error[113] DACTEST11.ASM 34 : Symbol not previously defined (trisb)
Error[113] DACTEST11.ASM 35 : Symbol not previously defined (trisb)
Error[113] DACTEST11.ASM 47 : Symbol not previously defined (wreg)
Error[113] DACTEST11.ASM 59 : Symbol not previously defined (portb)
Error[113] DACTEST11.ASM 75 : Symbol not previously defined (portb)
Jag har säkert bara glömt något, frågan är vad...
TRIS-felen försvinner om jag kör
movlw h'00' och movwf TRISC
movlw h'00' och movwf TRISB
Liknande grejj går att göra med PORTB, men rad47 (wreg) vet jag inte hur jag ska fixa.
Det bästa vore förstås om jag fixar orsaken till felmeddelandena.
Jag har haft mycket att göra, men nu är jag tillbaka.

Hm, fick några felmeddelande när jag körde 'build'.
Error[113] DACTEST11.ASM 32 : Symbol not previously defined (trisc)
Error[113] DACTEST11.ASM 33 : Symbol not previously defined (trisc)
Error[113] DACTEST11.ASM 34 : Symbol not previously defined (trisb)
Error[113] DACTEST11.ASM 35 : Symbol not previously defined (trisb)
Error[113] DACTEST11.ASM 47 : Symbol not previously defined (wreg)
Error[113] DACTEST11.ASM 59 : Symbol not previously defined (portb)
Error[113] DACTEST11.ASM 75 : Symbol not previously defined (portb)
Jag har säkert bara glömt något, frågan är vad...
TRIS-felen försvinner om jag kör
movlw h'00' och movwf TRISC
movlw h'00' och movwf TRISB
Liknande grejj går att göra med PORTB, men rad47 (wreg) vet jag inte hur jag ska fixa.
Det bästa vore förstås om jag fixar orsaken till felmeddelandena.

- JimmyAndersson
- Inlägg: 26578
- Blev medlem: 6 augusti 2005, 21:23:33
- Ort: Oskarshamn (En bit utanför)
- Kontakt:
- JimmyAndersson
- Inlägg: 26578
- Blev medlem: 6 augusti 2005, 21:23:33
- Ort: Oskarshamn (En bit utanför)
- Kontakt:
Jo, det är tur...
Har kodat lite i MikroBasic nu: I min inline-asm har jag med det i din kod som ligger från "send2spi" till raden innan "goto loop". Men istället för att räkna upp dac_l och dac_h så plockar jag värdet som skickas till proceduren DAC_Output.
Nu ger MikroBasic inga felmeddelanden. Men det fungerar inte. Dvs, lysdioden blinkar inte, den är släckt hela tiden.
Märkte att du bara skickar nollor till DAC'en i början innan den stegar upp?
I mina tester har jag använt "11000000 00000000", i databladet står programbitarna "1100" för konfigurationen: "The DAC A output is updated on the rising clock edge after D0 is sampled." Men din kod verkar använda "Write data to DAC B and BUFFER" och "slow mode" dvs "0000" som programbitar.
Jag tolkade "Write data to DAC B and BUFFER" som att den inte använde DAC A, men det kanske är fel?
(Jag testade förstås även att sätta programbitarna till "0000".)
Ska prova att byta ut mer och mer i min kod mot inline-asm. Man kan kanske fråga sig varför jag inte kör assembler helt och hållet? Det är en bra fråga...
Svaret är: Eftersom jag har så mycket annan kod till slutprojektet i MikroBasic så skulle det ta för mycket tid att koda om allt till assembler...
edit: Skrev fel, kopierade inte koden från "loop" och framåt, däremot från "send2spi" och framåt...

Har kodat lite i MikroBasic nu: I min inline-asm har jag med det i din kod som ligger från "send2spi" till raden innan "goto loop". Men istället för att räkna upp dac_l och dac_h så plockar jag värdet som skickas till proceduren DAC_Output.
Nu ger MikroBasic inga felmeddelanden. Men det fungerar inte. Dvs, lysdioden blinkar inte, den är släckt hela tiden.
Märkte att du bara skickar nollor till DAC'en i början innan den stegar upp?
I mina tester har jag använt "11000000 00000000", i databladet står programbitarna "1100" för konfigurationen: "The DAC A output is updated on the rising clock edge after D0 is sampled." Men din kod verkar använda "Write data to DAC B and BUFFER" och "slow mode" dvs "0000" som programbitar.
Jag tolkade "Write data to DAC B and BUFFER" som att den inte använde DAC A, men det kanske är fel?
(Jag testade förstås även att sätta programbitarna till "0000".)
Ska prova att byta ut mer och mer i min kod mot inline-asm. Man kan kanske fråga sig varför jag inte kör assembler helt och hållet? Det är en bra fråga...

edit: Skrev fel, kopierade inte koden från "loop" och framåt, däremot från "send2spi" och framåt...
Senast redigerad av JimmyAndersson 16 november 2005, 00:54:14, redigerad totalt 1 gång.
- JimmyAndersson
- Inlägg: 26578
- Blev medlem: 6 augusti 2005, 21:23:33
- Ort: Oskarshamn (En bit utanför)
- Kontakt:
Oj, du har rätt. Jag behöver nog starkare glasögon... 
edit: Jag fortsätter förstås byta ut grejjer i min basic-kod och jämföra asm-koden med basic-koden, så du inte tror jag somnat...
Märker att mina assembler-kunskaper förbättras på detta sätt. Riktigt kul faktiskt.
En liten fråga som jag kanske borde fråga MikroElektronika egentligen, men du kanske vet svaret: När man använder inline-asm gör MikroBasic om den koden på något vis, eller blir resultatet likadant som om jag hade skrivit in asm-koden i t.ex MPLAB? (När jag visar asm-koden som MikroBasic genererar så ser jag inte mina inline-asm-rader....)
Assemblerkoden du gjorde fungerar, men inte när jag använder "send2spi", "first_byte_wait" och "sec_byte_wait" från din kod, som inline-asm. Frågan är varför...
Skickar med min kod som den ser ut just nu:
Jag har förresten ändrat CS så den ligger på PORTC,0 istället. Den ändringen fungerade när jag provade med hela assembler-filen i MPLAB.
edit 051116: Nu har jag skrivit om problemet i MikroElektronika's forum. Ska bli intressant att se vad de svarar...

edit: Jag fortsätter förstås byta ut grejjer i min basic-kod och jämföra asm-koden med basic-koden, så du inte tror jag somnat...
Märker att mina assembler-kunskaper förbättras på detta sätt. Riktigt kul faktiskt.
En liten fråga som jag kanske borde fråga MikroElektronika egentligen, men du kanske vet svaret: När man använder inline-asm gör MikroBasic om den koden på något vis, eller blir resultatet likadant som om jag hade skrivit in asm-koden i t.ex MPLAB? (När jag visar asm-koden som MikroBasic genererar så ser jag inte mina inline-asm-rader....)
Assemblerkoden du gjorde fungerar, men inte när jag använder "send2spi", "first_byte_wait" och "sec_byte_wait" från din kod, som inline-asm. Frågan är varför...
Skickar med min kod som den ser ut just nu:
Kod: Markera allt
const CHIP_SELECT = 0
dim value as word
sub procedure Init
ADCON1 = %00001111 ' Digitala A-portar!
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=1 ' SDI till ingång.
SetBit(TRISC,CHIP_SELECT) ' Ska vara hög innan den blir låg.
'Initierar SPI till DAC-kretsen (TLV 5618A) --------------
SSPSTAT.SMP=0 ' Input data sampled at the MIDDLE of data output time.
SSPSTAT.CKE=0 ' Data skickas on falling edge of SCK
SSPSTAT.5=0
SSPSTAT.4=0
SSPSTAT.3=0
SSPSTAT.2=0
SSPSTAT.1=0
SSPSTAT.0=0
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/64
SSPCON1.SSPM2=0 ' Master mode, clock = Fosc/64
SSPCON1.SSPM1=1 ' Master mode, clock = Fosc/64
SSPCON1.SSPM0=0 ' Master mode, clock = Fosc/64
end sub
sub procedure DAC_Output(dim value as word)
dim dac_h as byte
dim dac_l as byte
dac_h = hi(value) ' Förbered bit 15-8
dac_l = lo(value) ' Förbered bit 7-0
asm
send2spi
bcf portc,0 ; Enable CS
movff dac_h, SSPBUF ; First byte
first_byte_wait
btfss SSPSTAT, BF ; Wait for BF flag.
bra first_byte_wait
movf SSPBUF, W ; Dummy read...
movff dac_l, SSPBUF ; Second byte
sec_byte_wait
btfss SSPSTAT, BF ; Wait for BF flag.
bra sec_byte_wait
movf SSPBUF, W ; Dummy read...
bsf portc,0 ; Disable CS
end asm
end sub
main:
init
while true
value = %1000000000000000
DAC_Output(value) 'Skickar
delay_ms(500)
value = %1000111111111111
DAC_Output(value) 'Skickar
delay_ms(500)
wend
end.
edit 051116: Nu har jag skrivit om problemet i MikroElektronika's forum. Ska bli intressant att se vad de svarar...
- JimmyAndersson
- Inlägg: 26578
- Blev medlem: 6 augusti 2005, 21:23:33
- Ort: Oskarshamn (En bit utanför)
- Kontakt:
Har fått lite tips på MikroElektronika's forum:
Någon föreslog att jag skulle köra med Fosc/16 eftersom slave-enheten kan ha problem att hänga med i höga hastigheter. Tyvärr hjälpte det inte.
Ett annat tips handlade också om timing, men att man behövde skicka en 17e bit så att SCLK fick ytterligare en puls för att hamna rätt.
Så här alltså:
Note: After transfer of the LSB during a data or control write cycle, one additional rising edge on SCLK is required to reset the internal state machine. This edge can occur when CS is high or low, but must occur before the next falling CS edge that begins the following write cycle. Refer to the timing diagram for more information.
Det hjälpte inte heller. Frågade ytterligare en gång varför inte MikroBasic's egna rutiner/library fungerar och varför det fungerar i assembler när man bara skickar 16bits (så att SCLK får 16 pulser). Väntar på svar om detta därifrån nu...
Fick tips om att använda en annan DAC: MCP4922, men det känns onödigt eftersom det inte är något fel på TLV5618A....
Någon föreslog att jag skulle köra med Fosc/16 eftersom slave-enheten kan ha problem att hänga med i höga hastigheter. Tyvärr hjälpte det inte.
Ett annat tips handlade också om timing, men att man behövde skicka en 17e bit så att SCLK fick ytterligare en puls för att hamna rätt.
Så här alltså:
Note: After transfer of the LSB during a data or control write cycle, one additional rising edge on SCLK is required to reset the internal state machine. This edge can occur when CS is high or low, but must occur before the next falling CS edge that begins the following write cycle. Refer to the timing diagram for more information.
Det hjälpte inte heller. Frågade ytterligare en gång varför inte MikroBasic's egna rutiner/library fungerar och varför det fungerar i assembler när man bara skickar 16bits (så att SCLK får 16 pulser). Väntar på svar om detta därifrån nu...

Fick tips om att använda en annan DAC: MCP4922, men det känns onödigt eftersom det inte är något fel på TLV5618A....
Så vitt jag förstår, så är den assmebler som MikroBasic använder inline, inte densamma som den man kör i MPLAB/MPASM. Det verkar saknas stöd för en del inbyggda directiv (som BANKSEL) o.s.v. Ä rdock lite osäker eftersom jag inte har kört inline asm i M-B själv...
När du ändå är på forumet skulle du kunna fråga om någon bättre dokumentation en den som finns i User Guide. Det är ju bara en halv sida....
> (När jag visar asm-koden som MikroBasic genererar så ser jag inte mina inline-asm-rader....)
Det verkar konstigt, lite dåligt om det är så.
När du ändå är på forumet skulle du kunna fråga om någon bättre dokumentation en den som finns i User Guide. Det är ju bara en halv sida....
> (När jag visar asm-koden som MikroBasic genererar så ser jag inte mina inline-asm-rader....)
Det verkar konstigt, lite dåligt om det är så.
- JimmyAndersson
- Inlägg: 26578
- Blev medlem: 6 augusti 2005, 21:23:33
- Ort: Oskarshamn (En bit utanför)
- Kontakt:
Ska fråga om bättre dokumentation, bra idé!
Jag fick en kod av en användare på det forumet, gjord med MikroBasic's egna rutiner/librarys.
Tro det eller ej, men den koden fungerar!
Skillnaderna mot min kod (när jag använde MikroBasic's rutiner) är att den här varianten har nop-"delay" och skickar en extra byte till DAC'en.
Tack för assembler-koden och all hjälp med detta problem!
Här är koden som jag fick från "xor" på MikroElektronika's forum:
edit: När jag byter ut while-loopen mot nedanstående kod så blir det en snygg upp-toning av lysdioden. (Skrev programbitarna binärt för att det ska vara lättare att se. $C000 hade inte sagt lika mycket.)
Så nu kan jag börja jobba med mitt ursprungliga projekt. Kul!
Jag fick en kod av en användare på det forumet, gjord med MikroBasic's egna rutiner/librarys.
Tro det eller ej, men den koden fungerar!

Skillnaderna mot min kod (när jag använde MikroBasic's rutiner) är att den här varianten har nop-"delay" och skickar en extra byte till DAC'en.
Tack för assembler-koden och all hjälp med detta problem!
Här är koden som jag fick från "xor" på MikroElektronika's forum:
Kod: Markera allt
const CHIP_SELECT = 0
dim value as word
sub procedure Init
ADCON1 = $0F ' ADCON1 = %00001111 ' Digital A-ports!
TRISA = 0 ' TESTLED's
PORTA = 0
TRISB = 0 ' LCD
PORTB = 0
TRISC = 0
PORTC = 0
SPI_INIT_ADVANCED(MASTER_OSC_DIV16, DATA_SAMPLE_MIDDLE, CLK_IDLE_LOW, LOW_2_HIGH)
ClearBit(TRISC,CHIP_SELECT) ' ChipSelect(RC0) direction is output
SetBit(PORTC, CHIP_SELECT) ' Disable CS
end sub
sub procedure DAC_Output(dim _value as word)
dim temp_hi as byte
dim temp_lo as byte
ClearBit(PORTC,CHIP_SELECT) ' Enable CS
temp_hi = hi(_value)
temp_lo = lo(_value)
SPI_WRITE(temp_hi)
SPI_WRITE(temp_lo)
nop '@40MHz some delay may be necessary
nop
SetBit(PORTC,CHIP_SELECT) ' Disable CS
SPI_WRITE($00) ' adds the 17th SCLK Pulse and then some
end sub
main:
Init
While true
value = %1100000000000000
DAC_Output(value) ' Sending
delay_ms(500)
value = %1100111111111111
DAC_Output(value) ' Sending
delay_ms(500)
Wend
end.
edit: När jag byter ut while-loopen mot nedanstående kod så blir det en snygg upp-toning av lysdioden. (Skrev programbitarna binärt för att det ska vara lättare att se. $C000 hade inte sagt lika mycket.)
Kod: Markera allt
While true
prog = %1100000000000000 ' Programbitarna
for x = 0 to 4095 step 7
value = prog or x ' Slår ihop programbitarna med databitarna
DAC_Output(value) ' Sending
delay_ms(10)
next x
Wend
Så nu kan jag börja jobba med mitt ursprungliga projekt. Kul!

- Greve Hamilton
- EF Sponsor
- Inlägg: 544
- Blev medlem: 4 september 2004, 15:03:35
- Ort: GBG
- JimmyAndersson
- Inlägg: 26578
- Blev medlem: 6 augusti 2005, 21:23:33
- Ort: Oskarshamn (En bit utanför)
- Kontakt:
DeeJayPA & GreveHamilton: Tack!
Otroligt att man kan hålla på så länge för att lösa ett problem. Jag började på våren 1937......
ok, kanske inte, men det känns så.
-Sedan är det förstås så att det alltid bara behövs små förändringar för att det ska fungera...
-Mitt första kod-test ser nästan likadant ut som den koden som fungerar!

Otroligt att man kan hålla på så länge för att lösa ett problem. Jag började på våren 1937......


-Sedan är det förstås så att det alltid bara behövs små förändringar för att det ska fungera...
-Mitt första kod-test ser nästan likadant ut som den koden som fungerar!
