AD9833 met PIC en MikroBasic

Bavelt

Golden Member

Er is nog wel iets raars aan de hand:
Ik moet de reset van de PIC laag houden, pas dan blijft de AD9833 output leveren.

Gisteren werkte het toevallig, omdat ik geen pull-up aan de Reset had hangen...

Wat zit er hier dan fout?


'====================================================================================================
Program Signal
'====================================================================================================

Dim   DDS_Value As LongInt                              'Divider value for the AD9833Dim DDS_SYNC As sBit At PortB.0
      DDS_CLK   As sBit At LATB.1                       'Change if needed
      DDS_DATA  As sBit At LATB.2                       '
      DDS_SYNC  As sBit At LATB.3                       '
      DDS          As Word                              'DDS ctrl register. Bits used
      DDS_Array    As Byte[2] At DDS

Const DDS_Mode    = 1                                   'in the AD9833 control register
      DDS_Div2    = 3                                   '
      DDS_OpBiten = 5                                   '
      DDS_Sleep12 = 6                                   '
      DDS_Sleep1  = 7                                   '
      DDS_Reset   = 8                                   '
      DDS_PSelect = 10                                  '
      DDS_FSelect = 11                                  '
      DDS_HLB     = 12                                  '
      DDS_B28     = 13                                  '
      DDS_Freq0   = 14                                  '
      DDS_Freq1   = 15

'==================================================================================================
Sub Procedure ChangeBit(Dim pBitnr As Byte, Dim pValue As Byte)
'==================================================================================================
  DDS_Array[pBitnr And 0x1000].(pBitnr And 0x0111) = pValue 'And 0x0111 = pValue
End Sub

'==================================================================================================
Sub Procedure SoftSpi_Write(Dim pVal As Word)
'==================================================================================================
  Dim lCnt As Byte
  DDS_SYNC = 1
  DDS_CLK  = 1
  DDS_SYNC = 0
  For lCnt = 0 to 15
    DDS_DATA = (pVal >> lCnt) And 0x0001
    DDS_CLK  = 0
    DDS_CLK  = 1
  Next lCnt
  DDS_CLK  = 0
  DDS_SYNC   = 1
End Sub

'==================================================================================================
Sub Procedure DDS_Init()                                            'Init the DDS chip
'==================================================================================================
  DDS_SYNC    = 0                                                  'Select DDS chip (spi #1)
  DDS         = 0                                                  'All Flags are '0'
  ChangeBit(DDS_Reset, 1)                                          '(except the reset flag)
  SoftSpi_Write(DDS)                                               '
  ChangeBit(DDS_Reset, 0)                                          '
  SoftSpi_Write(DDS)                                               '
  DDS_SYNC    = 1                                                  'Disable chip
End Sub                                                            '

'==================================================================================================
Sub Procedure DDS_Set()                                            'Set value from DDS_Value into the DSS chip
'==================================================================================================
  DDS_SYNC = 0                                                     'Select DDS chip (spi #1)
  SoftSpi_Write(0x2000)                                            'Set 2x14bits cmd mode
  SoftSpi_Write((DDS_Value And 0x00003FFF) Or 0x4000)              'Low 14 bit word first
  SoftSpi_Write((DDS_Value >> 14) Or 0x4000)                       'Hi 14 bits
  DDS_SYNC = 1                                                     '
End Sub                                                            '

Main:


  ANSELA     =  %00000000                             'All Port A Digital
  ANSELB     =  %00000000                             'All Port B Digital
  TRISA      =  %00100000                             'Port A.5 input
  TRISB      =  %00000000                             'All Port B Output
  OSCCON     =  %01111000                             '16 MHz internal

  DDS_INIT()
  DDS_SET()

  End.
Fouten zijn het bewijs dat je het probeert..
Bavelt

Golden Member

Aanvulling:

Ik moet dan:


While True
 DDS_SET()
Wend 

doen.

En dan de resetknop vast blijven houden (A.5 naar GND).

Pas dan blijft hij lopen. Krijg je wel lamme vingers van.. ;(

Fouten zijn het bewijs dat je het probeert..

Kennelijk doet je programma iets met de DDS wat hem inspereert om "niets" te doen.

Zodra je de reset indrukt zal je CPU "helemaal niets" kunnen doen en gaat de AD9833 ineens iets doen. Ehh. Tja, kennelijk doe je iets verkeerd wat de AD9833 dus blokkert om een uitvoer te geven.

Dat kan zijn dat ie denkt dat je nog aan het configureren bent.

Als test kan je alle outputs naar de AD9833 even als inpout zetten (doet de reset ook!) en kijk of het dan wel werkt.

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
Arco

Special Member

Als je de 3 regels met 'DDS_SYNC' in de SoftSpiWrite routine disabled, werkt 't dan wel?

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

Golden Member

Beide geprobeerd, maar geen resultaat.
Wat wel raar is, dat heel af en toe de puls output komt.
maar dan wel staat te klapperen met ca 0,5 Hz.

Daarom heb ik een nieuwe breadboard gepakt en opnieuw opgezet met nieuwe draadbrugjes.

En de soldeerverbinding van de header op het kleine AD9833 printje opnieuw even gedaan.

Maar het helpt niet.

Er moet iets zijn.

Het is toch niet de bedoeling dat DDS_SET in een While - wend loop zit?
M.a.w. één keer instellen dan moet het ding toch blijven draaien?

Fouten zijn het bewijs dat je het probeert..
Arco

Special Member

Je stelt de frequentie maar een maal in (en wanneer die verandert uiteraard)
Werkt in 5 apparaten hier al 8 jaar (met 24f) zonder problemen...

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Arco

Special Member

Wat ik bedacht:

Je gebruikt een of andere kant en klaar interfaceprintje?
Zit daar wel een clockgenerator op? Indien niet, dan moet je op MCLK ook nog een kloksignaal aanbieden! (bijv. van de reference clock module)
(ik nam eigenlijk aan dat die er al op zat, maar dat hoeft niet)

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

Golden Member

Er zit helemaal geen MCLK op..

Deze AD9833 is een printje dat ook in Arduino sketches wordt gebruikt, zonder verdere hardware. Dat werkt daar ook.
Het genereert een blok, sinus of driehoek signaal.
Ik ging er ook van uit dat het ding een oscillator aan boord heeft.

Op het zilveren componentje staat L 25.0. Is dat geen oscillator (of kristal) van 25 Mhz?

[Bericht gewijzigd door Bavelt op donderdag 19 december 2024 19:57:23 (12%)

Fouten zijn het bewijs dat je het probeert..
Bavelt

Golden Member

Ik heb het printje nog even getest met de Arduino, die werkt goed (geen losse contacten op het printje):


#include <AD9833.h>      // Include the library
#define FNC_PIN 10       // Can be any digital IO pin
#define Frequency 1000   // Frequency = 1Hz

//--------------- Create an AD9833 object ----------------
// Note, SCK and MOSI must be connected to CLK and DAT pins on the AD9833 for SPI
AD9833 gen(FNC_PIN);       // Defaults to 25MHz internal reference frequency

void setup() {
  Serial.begin(9600);
  // This MUST be the first command after declaring the AD9833 object
  gen.Begin();

  // Apply a 1000 Hz sine wave using REG0 (register set 0). There are two register sets: REG0 and REG1.
  // Each one can be programmed for:
  //   Signal type - SINE_WAVE, TRIANGLE_WAVE, SQUARE_WAVE, and HALF_SQUARE_WAVE
  //   Frequency - 0 to 12.5 MHz
  //   Phase - 0 to 360 degress (this is only useful if it is 'relative' to some other signal
  //           such as the phase difference between REG0 and REG1).
  // In ApplySignal, if Phase is not given, it defaults to 0.
  gen.ApplySignal(SINE_WAVE, REG0, Frequency);  
  gen.EnableOutput(true);   // Turn ON the output - it defaults to OFF
  // There should be a 1 Hz square wave on the output of the AD9833
}

void loop() {
}
Fouten zijn het bewijs dat je het probeert..
Arco

Special Member

Op het zilveren componentje staat L 25.0. Is dat geen oscillator (of kristal) van 25 Mhz?

Dat zal de oscillator zijn die aan MCLK vast zit, daar wordt de uitgangsfrequentie mee gemaakt/ van afgeleid.

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

Golden Member

Vermoedde ik al.
Maar ondertussen heb ik de PIC i.c.m. het ding nog niet aan de praat.

De hardware is goed, er moet iets zijn in het MB programma dat maakt dat de AD9833 zwijgt.

Wellicht toch nog een enable/disable output flag?

Fouten zijn het bewijs dat je het probeert..
Arco

Special Member

Die .h file staat niks zinvols in, alleen declaraties...
Zou het wel willen uittesten, maar heb hier alleen losse (msop10 is wat lastig... :) )

Dit kun je nog proberen:


'==================================================================================================
Sub Procedure SoftSpi_Write(Dim pVal As Word)
'==================================================================================================
  Dim lCnt As Byte
  DDS_CLK  = 1
  DDS_SYNC = 0
  For lCnt = 0 to 15
    DDS_DATA = (pVal >> lCnt) And 0x0001
    DDS_CLK  = 0
    DDS_CLK  = 1
  Next lCnt
End Sub

[Bericht gewijzigd door Arco op vrijdag 20 december 2024 01:31:45 (84%)

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

Golden Member

Dat helpt ook niet.

Het enige wat nu werkt is als je in de main:


While True
    DDS_SET()
  Wend

En dan de resetknop vast blijven houden (MCLR op A.5 enabled).

Dan komt er een keurige sinus uit van 15.625 Hz.

Edit: ik zie wel bij loslaten van Reset knop kleine piefjes op de output met 1 Mhz frequentie.

[Bericht gewijzigd door Bavelt op vrijdag 20 december 2024 10:30:43 (16%)

Fouten zijn het bewijs dat je het probeert..
Arco

Special Member

Je zou met de scoop het SPI signaal kunnen bekijken (en eventueel vergelijken met de Arduino versie?

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

Golden Member

Een routine in de Arduino Sketch die de frequentie regelt:


 *  Set the specified frequency register with the frequency (in Hz)
 */
void AD9833 :: SetFrequency ( Registers freqReg, float frequency ) {
	// TODO: calculate max frequency based on refFrequency.
	// Use the calculations for sanity checks on numbers.
	// Sanity check on frequency: Square - refFrequency / 2
	//							  Sine/Triangle - refFrequency / 4
	if ( frequency > 12.5e6 )	// TODO: Fix this based on refFreq
		frequency = 12.5e6;
	if ( frequency < 0.0 ) frequency = 0.0;
	
	// Save frequency for use by IncrementFrequency function
	if ( freqReg == REG0 ) frequency0 = frequency;
	else frequency1 = frequency;
	
	int32_t freqWord = (frequency * pow2_28) / (float)refFrequency;
	int16_t upper14 = (int16_t)((freqWord & 0xFFFC000) >> 14), 
			lower14 = (int16_t)(freqWord & 0x3FFF);

	// Which frequency register are we updating?
	uint16_t reg = freqReg == REG0 ? FREQ0_WRITE_REG : FREQ1_WRITE_REG;
	lower14 |= reg;
	upper14 |= reg;   

	// I do not reset the registers during write. It seems to remove
	// 'glitching' on the outputs.
	WriteControlRegister();
	// Control register has already been setup to accept two frequency
	// writes, one for each 14 bit part of the 28 bit frequency word
	WriteRegister(lower14);			// Write lower 14 bits to AD9833
	WriteRegister(upper14);			// Write upper 14 bits to AD9833
}

Wat een abracadabra... ;(

Ze zeggen wel eens over dat C: "Write once, read never...."

Fouten zijn het bewijs dat je het probeert..
Bavelt

Golden Member

Op vrijdag 20 december 2024 10:36:51 schreef Arco:
Je zou met de scoop het SPI signaal kunnen bekijken (en eventueel vergelijken met de Arduino versie?

Het SPI signaal komt natuurlijk maar even? (behalve nu ik het even in een loop heb gestopt)

De Soft SPI heeft ook geen SPI_Init nodig?

Fouten zijn het bewijs dat je het probeert..
Arco

Special Member

Geen init nodig (is alleen het togglen van een paar i/o lijnen)
Signaal is inderdaad heel kort...

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Arco

Special Member

Wat een abracadabra... ;(

+1   :)

De routines WriteControlRegister en WriteRegister zie ik nergens?

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

Golden Member

Zou dit moeten zijn..



// --------------------- PRIVATE FUNCTIONS --------------------------

/*
 * Write control register. Setup register based on defined states
 */
void AD9833 :: WriteControlRegister ( void ) {
	uint16_t waveForm;
	// TODO: can speed things up by keeping a writeReg0 and writeReg1
	// that presets all bits during the various setup function calls
	// rather than setting flags. Then we could just call WriteRegister
	// directly.
	if ( activeFreq == REG0 ) {
		waveForm = waveForm0;
		waveForm &= ~FREQ1_OUTPUT_REG;
	}
	else {
		waveForm = waveForm1;
		waveForm |= FREQ1_OUTPUT_REG;
	}
	if ( activePhase == REG0 )
		waveForm &= ~PHASE1_OUTPUT_REG;
	else
		waveForm |= PHASE1_OUTPUT_REG;
	if ( outputEnabled )
		waveForm &= ~RESET_CMD;
	else
		waveForm |= RESET_CMD;
	if ( DacDisabled )
		waveForm |= DISABLE_DAC;
	else
		waveForm &= ~DISABLE_DAC;
	if ( IntClkDisabled )
		waveForm |= DISABLE_INT_CLK;
	else
		waveForm &= ~DISABLE_INT_CLK;

	WriteRegister ( waveForm );
}

void AD9833 :: WriteRegister ( int16_t dat ) {
	/*
	 * We set the mode here, because other hardware may be doing SPI also
	 */
	SPI.setDataMode(SPI_MODE2);

	/* Improve overall switching speed
	 * Note, the times are for this function call, not the write.
	 * digitalWrite(FNCpin)			~ 17.6 usec
	 * digitalWriteFast2(FNC_PIN)	~  8.8 usec
	 */
	WRITE_FNCPIN(LOW);		// FNCpin low to write to AD9833

	//delayMicroseconds(2);	// Some delay may be needed

	// TODO: Are we running at the highest clock rate?
	SPI.transfer(highByte(dat));	// Transmit 16 bits 8 bits at a time
	SPI.transfer(lowByte(dat));

	WRITE_FNCPIN(HIGH);		// Write done
}


Fouten zijn het bewijs dat je het probeert..

Op vrijdag 20 december 2024 10:42:54 schreef Bavelt:
Ze zeggen wel eens over dat C: "Write once, read never...."

Sorry hoor, maar dat is duidelijke code die prima te lezen is.

Wat in de arduino code fout gaat is dat je de output enabled nadat je de frequentie hebt ingesteld. Tijdens het frequentie instellen wordt "writecontrolregister" aangeroepen met "output uit" toestand.

Anders zou het zo kunnen zijn dat je nog een nieuwe setfrequency of zoiets moet aanroepen.

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
Bavelt

Golden Member

Maar de Arduino werkt juist.
Het is de code in MikroBasic waar iets fout gaat..

Fouten zijn het bewijs dat je het probeert..

Main:
  ANSELA     =  %00000000    'All Port A Digital
  ANSELB     =  %00000000    'All Port B Digital
  TRISA      =  %00100000    'Port A.5 input
  TRISB      =  %00000000    'All Port B Output
  OSCCON     =  %01111000    '16 MHz internal

  DDS_INIT()
  DDS_SET()

  End.

Ik heb geen verstand van basic. Maar ik vraag me wel af wat er gebeurt als het programma klaar is? Begint alles dan niet opnieuw? Ik zou een endless loop verwachten aan het eind.

Arco

Special Member

Eigenlijk hoort er een while...wend loop in main om de boel draaiende te houden.
De compiler zet wel een eindeloze loop neer ipv end., maar netjes is het niet om daarop te vertrouwen...

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

Golden Member

Normaliter zit er ook altijd wel een While .. - Wend loop in mijn MB-programma's.

In dit geval was er niet echt een loop nodig.
Maar ik heb hem voor de netheid er toch maar even in gezet.

Niet dat dit helpt; er komt nog steeds niets uit de output van de AD9833...

Fouten zijn het bewijs dat je het probeert..
Bavelt

Golden Member

Ik ben nog steeds aan het worstelen met mijn AD9833.

Ik vond een aardig filmpje op Youtube, waarin duidelijk wordt uitgelegd hoe de structuur van de registers van dit device in elkaar zit, met een voorbeeld wat je moet doen om een 400 Hz sinus te krijgen.

En ik heb even teruggegrepen op een werkend programmaatje dat met de hardware SPI werkt op mijn PIC 16F1847.

En dit aangepast om een word te kunnen versturen.

Dit is dan mijn programma:



'====================================================================================================
Program Signal
' SDO (D1):     LATB.2                   Pin 8
' SCK (D0):     LATB.4                   Pin 10
' C_S           LATB.3                   Pin 9
'====================================================================================================

Dim ClockPin As sbit at LATB.4           'pin 10                   'Clock
    Datapin  As sbit at lATB.2           'pin 8                    'SDO
    C_S      As sbit at LATB.3           'pin 9                    'Chip Select

'====================================================================================================
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

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
  delay_ms(100)

  C_S = 0
  SPI1_Init()
  Delay_ms(100)
  
  C_S = 1

  Write_Reg(0x0000)
  Write_Reg(0x0100)
  Write_Reg(0x2100)
  Write_Reg(0x50C7)
  Write_Reg(0x4000)
  Write_Reg(0xC000)
  Write_Reg(0x2002)

  C_S = 1

  While True                                          'Dummy loop
  Wend

  End.

Maar waarom, o waarom werkt dit nu niet?
Er moet iets fout gaan bij het schrijven naar de registers.

De link naar het artikeltje:

https://youtu.be/8f0b7SpJpI0?feature=shared

Fouten zijn het bewijs dat je het probeert..