Sub Procedure Write_Reg(dim pDat as Word)
'====================================================================================================
 C_S = 1
 Spi_Write(pDat)
 Spi_Write (pDat >>8)
 C_S = 0
 Delay_ms(20)
End Sub

Ik zou denken dat C_S (FSYNC) laag moet zijn tijdens een SPI transfer.

Ik heb het omgedraaid:



'====================================================================================================
Sub Procedure Write_Reg(dim pDat as Word)
'====================================================================================================
 C_S = 0
 Spi_Write(pDat)
 Spi_Write (pDat >>8)
 C_S = 1
 Delay_ms(20)
End Sub

De AD9833 lijkt er wel op te reageren. De uitkomst is echter wat onvoorspelbaar. Er komt af en toe na spanning er op zetten een blokgolf uit van 286,4 hz.
Maar het reageert niet op het commando voor andere outputvorm. Ook de frequentie instellen levert rare dingen op.

Na de eerste Spi_Write() aanroep even een bitje ergens in een register monitoren dat aangeeft dat de data volledig verstuurd is. En dan pas de volge de aanroep naar Spi_Write() doen. Of wacht Spi_Write() zelf totdat de actie klaar is (blokkerende functie)?
Kijk ook naar de timing, er is vast een prescaler te configureren die de snelheid van je Spi peripheral bepaalt. Kijk ook goed naar op welke flank van de klok de data overgenomen wordt door de AD9833, en zorg dat je MCU overeenkomstig geconfigureerd is.

Dit was inderdaad wel een goede tip van Arco! ;)

Het programma uit de link oogde wat rommelig, met veel uitgeschakelde instructies, alternatieven, etc.
Bovendien was het voor een PIC16F690, die heb ik niet.
Daarom heb ik het maar omgezet naar mijn vertrouwde PIC16F1847 en de zaak wat vereenvoudigd.
En warempel het werkt na die aanpassingen ook nog!

Dit werd het voor even:


Program SPI_v14

dim Control_reg as word   ' 16 bits
                    ' D15-D14=00 -> change of Control-reg
                    ' D13=1 : 28 bits sended in 2 writes in Freq_x registers
                    ' D13=0 : 14 bits sended MSB or LSB (D12)
                    ' D12=1/0 : MSB / LSB of Freq_x (D11)
                    ' D11=1/0 : Freq_1/0  register
                    ' D10=1/0 : Phase_1/0 register
                    ' D9=0    : reserved
                    ' D8=1    : Reset device
                    ' D7=1    : Sleep1 MCLK disabled
                    ' D6=1    : Sleep12 powerdown DAC
                    ' D5=1    : OPBITEN ... MSB or MSB/2 bit pass (D3)
                    ' D4=0    : reserved
                    ' D3=1    : DIV2 (MSB or MSB/2)
                    ' D2=0    : reserved
                    ' D1=1    : MODE (with D5) SIN or TRIANGLE output
                    '           !!! D1=0 if D5=1
                    ' D0=0    : reserved
dim f_sortie, freq, Freq0, Freq1 as longword
                     ' 2 Write with Control_reg D13=1 (28 bits)
                     ' D15=0 D14=1 then Freq0 + 14 register bits
                     ' D15=1 D14=0 then Freq1 + 14 register bits

Dim Phase0, Phase1 as word
                     ' D15=1 D14=1 D13=0 D12=x then Phase0 + 12 register bits
                     ' D15=1 D14=1 D13=1 D12=x then Phase1 + 12 register bits

' Definitions for SPI pins
dim Chip_Select as sbit at LATB.3
    CS_MCP as sbit at LATB.0
    SoftSpi_CLK as sbit at LATB.4
    'SoftSpi_SDI as sbit at LATB.1
    SoftSpi_SDO as sbit at LATB.2

dim Chip_Select_Direction as sbit at LATB.3
    CS_MCP_Direction as sbit at LATB.0
    SoftSpi_CLK_Direction as sbit at LATB.4
    'SoftSpi_SDI_Direction as sbit at LATB.1
    SoftSpi_SDO_Direction as sbit at LATB.2

sub procedure InitMain()
  SoftSpi_CLK_direction = 0
  'SoftSpi_SDI_direction = 1
  SoftSpi_SDO_direction = 0
  Chip_Select_Direction = 0     ' Set CS# pin as Output
  Chip_select = 1               '  FSINK = 1

  delay_us(100)
end sub

sub procedure SPI_Out(dim SPI_dat as word)
dim temp, i as byte
   SoftSPI_CLK = 1              ' SoftSPI_SDO = 0
   Chip_Select = 0              ' Select AD9833   FSYNC = 0 ...
    SoftSPI_SDO = SPI_DAT.15   SoftSPI_CLK = 0    SoftSPI_CLK = 1
    SoftSPI_SDO = SPI_DAT.14   SoftSPI_CLK = 0    SoftSPI_CLK = 1
    SoftSPI_SDO = SPI_DAT.13   SoftSPI_CLK = 0    SoftSPI_CLK = 1
    SoftSPI_SDO = SPI_DAT.12   SoftSPI_CLK = 0    SoftSPI_CLK = 1
    SoftSPI_SDO = SPI_DAT.11   SoftSPI_CLK = 0    SoftSPI_CLK = 1
    SoftSPI_SDO = SPI_DAT.10   SoftSPI_CLK = 0    SoftSPI_CLK = 1
    SoftSPI_SDO = SPI_DAT.9    SoftSPI_CLK = 0    SoftSPI_CLK = 1
    SoftSPI_SDO = SPI_DAT.8    SoftSPI_CLK = 0    SoftSPI_CLK = 1
    SoftSPI_SDO = SPI_DAT.7    SoftSPI_CLK = 0    SoftSPI_CLK = 1
    SoftSPI_SDO = SPI_DAT.6    SoftSPI_CLK = 0    SoftSPI_CLK = 1
    SoftSPI_SDO = SPI_DAT.5    SoftSPI_CLK = 0    SoftSPI_CLK = 1
    SoftSPI_SDO = SPI_DAT.4    SoftSPI_CLK = 0    SoftSPI_CLK = 1
    SoftSPI_SDO = SPI_DAT.3    SoftSPI_CLK = 0    SoftSPI_CLK = 1
    SoftSPI_SDO = SPI_DAT.2    SoftSPI_CLK = 0    SoftSPI_CLK = 1
    SoftSPI_SDO = SPI_DAT.1    SoftSPI_CLK = 0    SoftSPI_CLK = 1
    SoftSPI_SDO = SPI_DAT.0    SoftSPI_CLK = 0    SoftSPI_CLK = 1
      
   SoftSPI_CLK = 1
   Chip_Select = 1
   delay_us(10)
end sub

sub procedure Send_freq (dim freq as longword)
dim temp_MSB, temp_LSB as word
    freq = freq and 0x0FFFFFFF              '28 bits effective

    temp_LSB = loword(freq)                 ' LSB 14 bits
        temp_LSB.15=0  temp_LSB.14=1        ' freq0
        SPI_Out(temp_LSB)

    temp_MSB = hiword(freq * 4) div 4       ' MSB .. 2 bits to right
        temp_MSB.15=0  temp_MSB.14=1        ' freq0
        SPI_Out(temp_MSB)
end sub

main:


  ANSELA     =  %00000000                   'All Port A Digital
  ANSELB     =  %00000000                   'All Port B Digital
  TRISA      =  %00100000                   'Port A.5 input (MCLR)
  TRISB      =  %00000000                   'All Poert B Output
  OSCCON     =  %01110000                   '8Mhz internal
  
  InitMain()

  Control_reg=0x2100       ' B28=1 28 bits, D8 RESET ON,  D11=0 Freq0
  SPI_Out (Control_reg)
  f_sortie = 500
  freq0 = f_sortie * 10.73741824
  Send_freq(freq0)
  Phase0 = 0xC000
  SPI_Out (phase0)
  Control_reg=0x2002       ' B28=1 28 bits, D8 RESET Off,  D11=0 Freq0
  SPI_Out (Control_reg)

  While True Wend
  

end.

Maar ik wil natuurlijk wel uitzoeken waarom dit nu wel werkt en die van mij niet. Ze gebruiken hier overigens een Soft_SPI.
Ik heb voor het gemak de pinnen aangehouden voor de ingebouwde SPI van de 1847.
Ik wist alleen niet wat ik met de SoftSpi_SDI aan moest. Ik heb hem maar op de SDI Pin (B.1) gezet, maar volgens mij doet dat niks. Ik heb van die SDI instructie dan ook maar commentaar gemaakt.
En het blijft gewoon werken.

De pinnen dedinitie:



dim C_S         as sbit at LATB.3
    SoftSpi_CLK as sbit at LATB.4
    SoftSpi_SDO as sbit at LATB.2

Maar die 'Direction declaratie daaronder' hoeft toch niet persé?



'dim C_S_Direction as sbit at LATB.3
'    SoftSpi_CLK_Direction as sbit at LATB.4
'    SoftSpi_SDO_Direction as sbit at LATB.2

Zonder dit werkt het gewoon..

Het ziet er al wat appetijtelijker uit, nietwaar?


'====================================================================================================
Program SPI_v14
 'Device:       AD9833 Wave generator
' SDO (D1):     LATB.2  SDATA            Pin 8
' SCK (D0):     LATB.4  SCLK             Pin 10
' C_S           LATB.3  FSYNC            Pin 9
'====================================================================================================

Const Freq_Out  As LongWord = 1000

Dim Control_reg As word   ' 16 bits
                    ' D15-D14=00 -> change of Control-reg
                    ' D13=1 : 28 bits sended in 2 writes in Freq_x registers
                    ' D13=0 : 14 bits sended MSB or LSB (D12)
                    ' D12=1/0 : MSB / LSB of Freq_x (D11)
                    ' D11=1/0 : Freq_1/0  register
                    ' D10=1/0 : Phase_1/0 register
                    ' D9=0    : reserved
                    ' D8=1    : Reset device
                    ' D7=1    : Sleep1 MCLK disabled
                    ' D6=1    : Sleep12 powerdown DAC
                    ' D5=1    : OPBITEN ... MSB or MSB/2 bit pass (D3)
                    ' D4=0    : reserved
                    ' D3=1    : DIV2 (MSB or MSB/2)
                    ' D2=0    : reserved
                    ' D1=1    : MODE (with D5) SIN or TRIANGLE output
                    '           !!! D1=0 if D5=1
                    ' D0=0    : reserved

    Freq        As Longword
    Freq0       As Word
    Freq1       As Word

    Phase0      As word
    Phase1      As Word

    C_S         As sbit At LATB.3
    SoftSpi_CLK As sbit At LATB.4
    SoftSpi_SDO As sbit At LATB.2

'====================================================================================================
Sub procedure SPI_Out(dim SPI_dat As word)
'====================================================================================================
  Dim i1 As Byte
  SoftSPI_CLK = 1
  C_S = 0
 
  For i1 = 15 to 0 step -1
     SoftSPI_SDO = SPI_DAT.i1
     SoftSPI_CLK = 0    Delay_us(1)
     SoftSPI_CLK = 1    Delay_us(1)
  next i1

  C_S = 1
  Delay_us(10)
End sub

'====================================================================================================
Sub Procedure Send_freq (dim freq as longword)
'====================================================================================================
dim temp_MSB, temp_LSB as word
    freq = freq and 0x0FFFFFFF              '28 bits effective
    temp_LSB = loword(freq)                 'LSB 14 bits
    temp_LSB.15=0
    temp_LSB.14=1
    SPI_Out(temp_LSB)                       'freq0

    temp_MSB = hiword(freq * 4) div 4       'MSB .. 2 bits to right
    temp_MSB.15=0
    temp_MSB.14=1
    SPI_Out(temp_MSB)                       'freq0
end sub

Main:

  ANSELA     =  %00000000                   'All Port A Digital
  ANSELB     =  %00000000                   'All Port B Digital
  TRISA      =  %00100000                   'Port A.5 input (MCLR)
  TRISB      =  %00000000                   'All Poert B Output
  OSCCON     =  %01110000                   '8Mhz internal
  
  C_S = 1                                   'FSYNC = 1
  Delay_Ms(1)

  SPI_Out (0x2100)
  Freq0 = Freq_Out * 10.73741824
  Send_freq(freq0)
  SPI_Out (0xC000)
  SPI_Out (0x2028)                          'WaveForm Triangle

  While True Wend                           'Dummy endless loop

end.

het zou fijn zijn als ik mijn frequentiemetertje er aan kan hangen.
De output van de AD9833 is echter laag, zo'n 0,3 V komt er uit.
Te weinig voor mijn TTL-Schmitt-triggertje, dus moet ik het signaal iets versterken.
Ik heb een schakelingetje gezien waarbij er een OpAmp MCP601 wordt gebruikt.

Ik heb hier echter alleen een LM833 en een paar UA741. Die zijn meer bedoeld voor audio wat ik er van begrijp.
Maar om te testen zou het kunnen. Het zou wel fijn zijn als ik iets vind dat geen + en - voeding nodig heeft, maar gewoon werkt op 5V.

Is zo'n versterkertje ook met torren te maken? Het inputsignaal is wel heel klein..

Hier gaat nog iets niet goed met de formule.
Tot Freq_Out = 1525 gaat het helemaal goed.
Elke waarde daarboven geeft rare resultaten..

Edit: Ik ben er al uit.

Voor het schrijven van de MSB moet je beginnen met de ontbrekende bits die zijn weg gesloopt omdat bit 14 en 15 worden gebruikt voor het adres van het register freq0.

:)



Const Freq_Out  As LongWord = 1525
---
---

'====================================================================================================
Sub Procedure Send_freq (dim freq as longword)
'====================================================================================================
dim temp_MSB, temp_LSB as word
    freq = freq and 0x0FFFFFFF              '28 bits effective
    temp_LSB = loword(freq)                 'LSB 14 bits
    temp_LSB.15=0
    temp_LSB.14=1
    SPI_Out(temp_LSB)                       'freq0

    temp_MSB = hiword(freq * 4) div 4       'MSB .. 2 bits to right
    temp_MSB.15=0
    temp_MSB.14=1
    SPI_Out(temp_MSB)                       'freq0
end sub

[Bericht gewijzigd door Bavelt op (17%)]

Wat doet div 4? Als dat door 4 deelt is dat niet goed. Ik verwacht gewoon hiword (freq*4) daar.


temp_MSB = hiword(freq * 4) div 4

is een (wat omslachtige) manier om de hoogste bits '0' te maken...
Da's sowieso overbodig, want dat heeft de regel

 freq = freq and 0x0FFFFFFF 

al gedaan.


temp_MSB = hiword(freq)

zou moeten voldoen.

Volgens mij verlies je dan bit 14 en 15 van het frequentiewoord.

Je moet de 28 bits frequentiewoord schrijven als

01<bit0...13>
10<bit14...27>

hiword zal neem ik aan bit 16...bit31 pakken.

Freq*4 schoffelt bit 14 en 15 naar bit 16 en 17 (en alles daarboven schuift ook op. En dan is "highword" een efficiente manier om de 14 freqbits + 2 nulletjes bij mekaar te schoffelen.

Ik zelf zou schrijven:


   #define AD_FREQLO 0x4000
   #define AD_FREQHI 0x8000
   spi_out (((freqword >>  0) & 0x3fff) | AD_FREQLO);
   spi_out (((freqword >> 14) & 0x3fff) | AD_FREQHI);

De compiler zoekt maar uit hoe ie dat efficient doet. Merk op dat ik de & 0x0fffffff overbodig maak door 2x met de 14 gewenste bits te and-en.

Of zo:


'====================================================================================================
Sub Procedure Send_freq (dim freq as longword)
'====================================================================================================
    freq = (freq and 0x7FFF7FFF) or 0x40004000 '28 bits effective
    SPI_Out(hiword(freq))                      'freq0
    SPI_Out(loword(freq))                      'freq0
end sub

Nee, dat klopt niet.

Dat komt omdat bit 14 en 15 van de Lo(freq) worden weggepoetst en vervangen door 14 = 1, 15 = 0. (= adres freq0 register)

Je mist dan dus 2 bits van de LSB die moeten verschuiven naar de MSB.

Dat gebeurt dan door



 temp_MSB = Hiword(freq <<2)             'Shift 2 left because of bit 14/15 of LSB was ignored

Rest nu nog de output van de AD9833 te versterken.

De OpAmp MCP601 is hier niet verkrijgbaar. Wel een NE5534.

Deze ken ik niet, zou die zijn te gebruiken?

Op dinsdag 24 december 2024 11:31:43 schreef Bavelt:
Dat gebeurt dan door

Precies!

Als die bitjes weg mogen, dan had het

freq = (freq and 0x3FFF3FFF) or 0x80004000 

geweest.

Maar die bitjes zijn toch echt wel verdomd handig. Arco houdt wel degelijk 28 bitjes uit het "freq" woord over, maar dat zou freq compleet niet-lineair maken. Vandaar dat het in twee stappen moet.

Die NE5534 is niet bruikbaar. Die moet je met +/- 15V voeden (plus 15 en min 15), en dan is de common mode input range tot 3V uit de voedingsrails.

Neem een MCP6001 en je kan tot in de millivolts bij de voedingen komen. (ik ken de 6001/2/4, de "low power" versie van de 601/2/4).

Ik heb voor mezelf besloten om de -2 te gebruiken. 8 pins, niet heel veel groter dan de 1-opamp versie en 2 zijn niet veel groter dan de -4 versie. Dus niet ontzettend verspillend als je maar 1 of meer dan 2 nodig hebt. En dan maar 1 onderdeel op voorraad. Voor grote series kan je dat dan altijd nog herzien.

P.S. @Bavelt. Schrijf *4 en niet << 2 . De compiler is bekend met "fouten bij shiften van langere datatypes". Ik zou het niet riskeren.
PPS: Mijn AD9833 breakout-printje-uit-china is zojuist gearriveerd.

Op dinsdag 24 december 2024 12:56:54 schreef rew:

P.S. @Bavelt. Schrijf *4 en niet << 2 . De compiler is bekend met "fouten bij shiften van langere datatypes". Ik zou het niet riskeren.

Oh, ik had dat juist gedaan omdat ik dacht dat <<2 een meer natuurlijke bewerking is dan vermenigvuldigen met 4. :).

Je kunt een 16F1709 of 16F1769 gebruiken, daar zitten 2 rail to rail opamps (OPA's) in... :)

OPA_pic_TB3132.pdf

Of gebruik een van de comparators in de 1847...

[Bericht gewijzigd door Arco op (17%)]

Daar heb ik nog niet eens aan gedacht...

Weer een uitdaging, ik heb nog nooit met de comparators van de 1847 gewerkt...

Ik heb hier ook nog wel een PIC16F1936 liggen, die heeft ook 2 comparators rail-to-rail, maar geen OPA"s zo te zien.

Comparators gebruik ik heel vaak, o.a. voor audiodetectie (dtmf, tonen,...) en zero-cross detectie.
Er zijn niet zoveel 16F1x pics met OPA's, bij de 24F zie je die veel vaker.

Op dinsdag 24 december 2024 16:22:48 schreef Arco:
Comparators gebruik ik heel vaak, o.a. voor audiodetectie (dtmf, tonen,...) en zero-cross detectie.
Er zijn niet zoveel 16F1x pics met OPA's, bij de 24F zie je die veel vaker.

Is daar nog veel voor nodig om dat toe te passen qua registers?

Vermoedelijk een referentiespanning opgeven aan een van de ingangen, de andere voeden vanaf de output van de AD9833 en als hij de refspanning overstijgt krijg je een logische 1?

Je kunt de min van de comparator aan Gnd leggen, en het signaal via een condensator aan de plus van de comparator leggen.
(met een hoogohmige pull-down aan de comparator plus (1M of zo) om de juiste offset te hebben.)

Pin op analoog zetten, comparator enablen, en kiezen welke pinnen je wilt gebruiken. (de min van de comparator blijft intern)
De uitgang van de comparator is ook direct intern beschikbaar (met interrupt indien gewenst)

[Bericht gewijzigd door Arco op (12%)]

TS wil de ad9833 uitgang maal 10 oid doen, dan moeten alledrie de aansluitingen van de opamp naàr buiten. Afhankelijk van wat voor frequenties je wil doen, kan het zijn dat je een heftige opamp moet nemen. Dan is mcp6002 mogelijk helemaal niet geschikt: die is erg traag.

Comparators zijn vrij snel: 60nS response bij full-swing. (bij kleine signalen nog een stuk sneller,
En 0.3v input is meer als genoeg, hysteresis is 45mV.

Als de TS een comparator kan/wil gebruiken dan heb ik gemist waar ie mee bezig is.