Control the AD9833 with communication SPI protocol via RS232

Just starting out? Need help? Post your questions and find answers here.
Stephane Fonteyne
User
User
Posts: 27
Joined: Sun Sep 06, 2015 2:22 pm

Control the AD9833 with communication SPI protocol via RS232

Post by Stephane Fonteyne »

Hi all,

I have need SPI communication for the AD9833 is a DDS chip and communication with the serialport.
I have ready the hardware in the form of a board from analog devices.
I would now like to program the AD9833 with pure basic and communicate via the SPI protocol .
I never go a module where all SPI communication is implemented.
I don't find here SPI master functions. Can someone help me with implement this functies with the serialport.
I have buildin in my PC running windows XP a serialport connector RS232

The AD9833 from the Datasheet - Short Summary
===============================
- The frequency registers are 28 bits wide:
- with a 25 MHz clock rate, resolution of 0.1 Hz can be achieved;
- with a 1 MHz clock rate, the AD9833 can be tuned to 0.004 Hz resolution
- FREQ0_REG -> 28 bit ; FREQ1_REG -> 28 bit (datatype : Double Word)
- PHASE0_REG -> 12 bit : PHASE1_REG -> 14 bit (datatype : Word)
- CONTROL_REG -> 16 bit
- 10 bit DAC, Vout = 38 mV to 650 mV
- fMCLK = 25 MHz --> fOut = fMCLK / 4096
- VinH 2.8V (5V) and VinL 0.8V (5V) and Idd = 5 mA (5V)

1. CIRCUIT DESCRIPTION
================

a. NUMERICALLY CONTROLLED OSCILLATOR PLUS PHASE MODULATOR
------------------------------------------------------------------------------
- This consists of two frequency select registers,
- a phase accumulator,
- two phase offset registers,
- and a phase offset adder.
- The main component of the NCO is a 28-bit phase accumulator.
- Continuous time signals have a phase range of 0 to 2π.
- Outside this range of numbers, the sinusoid functions repeat themselves in a periodic manner
- The accumulator simply scales the range of phase numbers into a multibit digital word.
- The phase accumulator in the AD9833 is implemented with 28 bits
- The input to the phase accumulator can be selected from either the FREQ0 register or the FREQ1 register and is controlled by the FSELECT bit
- Following the NCO, a phase offset can be added to perform phase modulation using the 12-bit phase registers.
- The contents of one of these phase registers are added to the most significant bits of the NCO. The AD9833 has two phase registers

b. THE SINE ROM
--------------------
- it must be converted from phase information into a sinusoidal value.
- Because phase information maps directly into amplitude,
- the SIN ROM uses the digital phase information as an address to a lookup table and converts the phase information into amplitude
- Although the NCO contains a 28-bit phase accumulator, the output of the NCO is truncated to 12 bits
- because this would require a lookup table of 2 ^ 28 entries.
- This requires that the SIN ROM have two bits of phase resolution more than the 10-bit DAC.
- SINE ROM : 12 bits and DAC : 10 bits
- The SIN ROM is enabled using the mode bit (D1) in the control register

c. DIGITAL-TO-ANALOG CONVERTER (DAC)
==========================
- The DAC receives the digital words from the SIN ROM and converts them into the corresponding analog voltages.
- The DAC is configured for single-ended operation.

2. FUNCTIONAL DESCRIPTION
==================
a. SERIAL INTERFACE
------------------------
- The AD9833 has a standard 3-wire serial interface that is compatible with the SPI
- Data is loaded into the device as a 16-bit word under the control of a serial clock input, SCLK
- The FSYNC input is a level-triggered input that acts as a frame synchronization and chip enable
- Data can be transferred into the device only when FSYNC is low
- To start the serial data transfer, FSYNC should be taken low.
1) After FSYNC goes low, serial data is shifted into the input shift register of the device on the falling edges of SCLK for 16 clock pulses
2) FSYNC may be taken high after the 16th falling edge of SCLK
Note1 : FSYNC should be taken low, observing the minimum FSYNC-to-SCLK falling edge setup time, t7
Note2 : observing the minimum SCLK falling edge to FSYNC rising edge time, t8
3) Alternatively, FSYNC can be kept low for a multiple of 16 SCLK pulses and then brought high at the end of the data transfer.
4) In this way, a continuous stream of 16-bit words can be loaded while FSYNC is held low
5) FSYNC goes high only after the 16th SCLK falling edge of the last word loaded.
6) The SCLK can be continuous, or it can idle high or low between write operations

b) POWERING UP THE AD9833
----------------------------------
- The flowchart in Figure 26 shows the operating routine for the AD9833.
- When the AD9833 is powered up, the part should be reset.
- This resets the appropriate internal registers to 0 to provide an analog output of midscale
- the reset bit should be set to 1 until the part is ready to begin generating an output.
- A reset does not reset the phase, frequency, or control registers.
- These registers will contain invalid data and, therefore, should be set to known values by the user.
- The reset bit should then be set to 0 to begin generating an output.

c. LATENCY PERIOD
----------------------
- A latency period is associated with each asynchronous write operation in the AD9833
- If a selected frequency or phase register is loaded with a new word,
there is a delay of seven or eight MCLK cycles before the analog output changes
- The delay can be seven or eight cycles, depending on the position of the MCLK rising edge
when the data is loaded into the destination register

d. THE CONTROL REGISTER
-------------------------------
- The AD9833 contains a 16-bit control register that allows the user to configure the operation of the AD9833.
- All control bits other than the mode bit are sampled on the internal falling edge of MCLK.
- D15 and D14 must be set to logical "0"
- D13 ... D0 ---> are the control bits

1) D13 --> B28
*************
B28 = "1" (2 x 14 bits two consecutive writes)
........................................

- Two write operations are required to load a complete word into either of the frequency registers.
- B28 = 1 allows a complete word to be loaded into a frequency register in two consecutive writes
- The first write contains the 14 LSBs of the frequency word, and the next write contains the 14 MSBs
- The first two bits of each 16-bit word define the frequency register to which the word is loaded and should, therefore, be the same for both of the consecutive writes

B28 = "0" (Alternated writes)
............................................

- The write to the frequency register occurs after both words have been loaded; therefore, the register never holds an intermediate value.
- a complete 28-bit write
- the 28-bit frequency register operates as two 14-bit registers, one containing the 14 MSBs and the other containing the 14 LSBs.
- This means that the 14 MSBs of the frequency word can be altered independent of the 14 LSBs, and vice versa.
- To alter the 14 MSBs or the 14 LSBs, a single write is made to the appropriate frequency address
- Note : The control bit D12 (HLB) informs the AD9833 whether the bits to be altered are the 14 MSBs or 14 LSBs.

2) D12 = HLB
=========
- This control bit allows the user to continuously load the MSBs or LSBs of a frequency register while ignoring the remaining 14 bits
- This is useful if the complete 28-bit resolution is not required --> HLB is used in conjunction with D13 (B28)
- This control bit indicates whether the 14 bits being loaded are being transferred to the 14 MSBs or 14 LSBs of the addressed frequency register
- When D13 (B28) = "0" to be able to change the MSBs and LSBs of a frequency word separately D13 = "0" en D12 = "1"
- When D13 (B28) = "1", this control bit is ignored. HLB = "1" allows a write to the 14 MSBs of the addressed frequency register.
HLB = 0 allows a write to the 14 LSBs of the addressed frequency register

3) D11 = FSELECT "Select the Freq Register"
===========================
- The FSELECT bit defines whether the FREQ0 register or the FREQ1 register is used in the phase accumulator.

4) D10 = PSELECT "Select the Phase Register"
=============================
- The PSELECT bit defines whether the PHASE0 register or the PHASE1 register data is added to the output of the phase accumulator

5) D9 = This bit should be set to 0 (Reserved) .
===============================

6) D8 = RESET
==========
- Reset = 1 resets internal registers to 0, which corresponds to an analog output of midscale. Reset = 0 disables reset.
- This function is explained further in Table 13.

7) D07 = SLEEP1
===========
- SLEEP1 = "1", the internal MCLK clock is disabled, and the DAC output remains at its present value because the NCO is no longer accumulating
- SLEEP1 = "0", MCLK is enabled. This function is explained further in Table 14.

6) D06 = SLEEP12
===========
- SLEEP12 = 1 powers down the on-chip DAC. This is useful when the AD9833 is used to output the MSB of the DAC data.
- SLEEP12 = 0 implies that the DAC is active. This function is explained further in Table 14.

D5 = OPBITEN
==========
- The function of this bit, in association with D1 (mode), is to control what is output at the VOUT pin
- This is explained further in Table 15
- When OPBITEN = 1, the output of the DAC is no longer available at the VOUT pin.
Instead, the MSB (or MSB/2) of the DAC data is connected to the VOUT pin.
This is useful as a coarse clock source.
The DIV2 bit controls whether it is the MSB or MSB/2 that is output
- When OPBITEN = 0, the DAC is connected to VOUT. The mode bit determines whether it is a sinusoidal or a ramp output that is available

D4 = This bit must be set to 0. (Reserved)
===============================

D3 = DIV2
=======
- DIV2 is used in association with D5 (OPBITEN)
- This is explained further in Table 15
- When DIV2 = 1, the MSB of the DAC data is passed directly to the VOUT pin.
- When DIV2 = 0, the MSB/2 of the DAC data is output at the VOUT pin

D2 = This bit must be set to 0 (Reserved)

D1 = MODE
========
- This bit is used in association with OPBITEN (D5).
- The function of this bit is to control what is output at the VOUT pin when the on-chip DAC is connected to VOUT
- This bit should be set to 0 if the control bit OPBITEN = 1. This is explained further in Table 15
- When mode = 1, the SIN ROM is bypassed, resulting in a triangle output from the DAC
- When mode = 0, the SIN ROM is used to convert the phase information into amplitude information, which results in a sinusoidal signal at the output

D0 = This bit must be set to 0. (Reserved)
==========================

Summary Control Register
================
D15 = "0"
D14 = "0"
D13 = B28
D12 = HLB
D11 = FSELECT
D10 = PSELECT
D9 = "0"
D8 = RESET
D7 = SLEEP1
D6 = SLEEP12
D5 = OPBITEN
D4 = "0"
D3 = DIV2
D2 = "0"
D1 = MODE
D0 = "0"

e. FREQUENCY AND PHASE REGISTERS
............................................................
- The AD9833 contains two frequency registers and two phase registers
- FREQ0 (28 bits) --> FSELECT = "0"
Frequency Register 0. When the FSELECT bit = 0, this register defines the output
frequency as a fraction of the MCLK frequency.
- FREQ1 (28 bits) --> FSELECT = "1"
Frequency Register 1. When the FSELECT bit = 1, this register defines the output
frequency as a fraction of the MCLK frequency.

- PHASE0 (12 bits) --> PSELECT = "0"
Phase Offset Register 0. When the PSELECT bit = 0, the contents of this register are
added to the output of the phase accumulator.
- PHASE1 (12 bits) --> PSELECT = "1"
Phase Offset Register 1. When the PSELECT bit = 1, the contents of this register are
added to the output of the phase accumulator.

- The analog output from the AD9833 is : AnalogOut = (fMCLK / 2 ^ 28) * FREQREG
where FREQREG is the value loaded into the selected frequency register

- This signal is phase shifted by : PhaseOut = (2 * PI / 4096) * PHASEREG
where PHASEREG is the value contained in the selected phase register
The flowchart in Figure 28 shows the routine for writing to the frequency and phase registers of the AD9833.

1) Writing to a Frequency Register
=====================
- When writing to a frequency register, Bit D15 and Bit D14 give the address of the frequency register.
- Table 8. Frequency Register Bits
- D15 D14 D13 D0
"0" "1" MSB 14 FREQ0 REG bits LSB
"1" "0" MSB 14 FREQ1 REG bits LSB

- If the user wants to change the entire contents of a frequency register,
two consecutive writes to the same address must be performed
because the frequency registers are 28 bits wide

- The first write contains the 14 LSBs, and the second write contains the 14 MSBs
- For this mode of operation, the B28 (D13) control bit should be set to 1

Table 9. Writing 0xFFFC000 to the FREQ0 Register
==============================
- SDATA Input : 0010 0000 0000 0000 : Control word write (D15, D14 = "00", B28 = "1", HLB = "X"
- SDATA Input : 0100 0000 0000 0000 : FREQ0 register write (D15, D14 = 01), 14 LSBs = 0x0000)
- SDATA Input : 0111 1111 1111 1111 : FREQ0 register write ((D15, D14 = 01), 14 MSBs = 0x3FFF)

* In some applications, the user does not need to alter all 28 bits of the frequency register.
* With coarse tuning, only the 14 MSBs are altered, while with fine tuning, only the 14 LSBs are altered.
By setting the B28 (D13) control bit to 0, the 28-bit frequency register operates as
two, 14-bit registers, one containing the 14 MSBs and the other containing the 14 LSBs
* This means that the 14 MSBs of the frequency word can be altered independent of the 14 LSBs,
and vice versa
* Bit HLB (D12) in the control register identifies which 14 bits are being altered.

Table 10. Writing 0x3FFF to the 14 LSBs of the FREQ1 Register
- SDATA Input : 0000 0000 0000 0000 : Control word write (D15, D14 = 00), B28 (D13) = 0; HLB (D12) = 0, that is, LSBs
- SDATA Input : 1011 1111 1111 1111 : FREQ1 REG write (D15, D14 = 10), 14 LSBs = 0x3FFF

Table 11. Writing 0x00FF to the 14 MSBs of the FREQ0 Register
- SDATA Input : 0001 0000 0000 0000 : Control word write (D15, D14 = 00), B28 (D13) = 0, HLB (D12) = 1, that is, MSBs
- SDATA Input : FREQ0 REG write (D15, D14 = 01), 14 MSBs = 0x00FF

2) Writing to a Phase Register
------------------------------------------------
- When writing to a phase register, Bit D15 and Bit D14 are set to 11. Bit D13 identifies which phase register is being loaded.

Table 12. Phase Register Bits
*************************
D15 D14 D13 D12 D11 D0
"1" "1" "0" "X" MSB 12 PHASE0 bits LSB
"1" "1" "1" "X" MSB 12 PHASE1 bits LSB

f: RESET FUNCTION
--------------------------------------------
- The reset function resets appropriate internal registers to 0 to provide an analog output of midscale
- Reset does not reset the phase, frequency, or control registers
- When the AD9833 is powered up, the part should be reset
- To reset the AD9833, set the reset bit to 1.
- To take the part out of reset, set the bit to 0.
- A signal appears at the DAC to output eight MCLK cycles after reset is set to 0

Table 13. Applying the Reset Function
********************************
Reset Bit Result
0 No reset applied
1 Internal registers reset
f: SLEEP FUNCTION
*********************************
- Sections of the AD9833 that are not in use can be powered down to minimize power consumption.
- This is done using the sleep function.
- The parts of the chip that can be powered down are the internal clock and the DAC.

Table 14. Applying the Sleep Function
********************************
SLEEP1 Bit SLEEP12 Bit Result
0 0 No power-down
0 1 DAC powered down
1 0 Internal clock disabled
1 1 Both the DAC powered down and the internal clock disabled

a) DAC Powered Down : This is useful when the AD9833 is used to output the MSB of the DAC data only
b) Internal Clock Disabled :
When the internal clock of the AD9833 is disabled,
the DAC output remains at its present value because the NCO is no longer accumulating
New frequency, phase, and control words can be written to the part when the SLEEP1 control bit is active
The synchronizing clock is still active, which means that the selected frequency and phase registers can also be changed using the control bits
Setting the SLEEP1 bit to 0 enables the MCLK. Any changes made to the registers while SLEEP1 is active will be seen at the output after a latency period.

g. VOUT PIN
***************************
- The AD9833 offers a variety of outputs from the chip, all of which are available from the VOUT pin.
- The choice of outputs is the MSB of the DAC data, a sinusoidal output, or a triangle output
- The OPBITEN (D5) and mode (D1) bits in the control register are used to decide which output is available from the AD9833

MSB of the DAC Data

- The MSB of the DAC data can be output from the AD9833.
- By setting the OPBITEN (D5) control bit to 1, the MSB of the DAC data is available at the VOUT pin.
- This is useful as a coarse clock source.
- This square wave can also be divided by 2 before being output.
- The DIV2 (D3) bit in the control register controls the frequency of this output from the VOUT pin.

Sinusoidal Output
- The SIN ROM is used to convert the phase information from the frequency and phase registers into amplit ude information
that results in a sinusoidal signal at the output.
- To have a sinusoidal output from the VOUT pin, set the mode (D1) bit to 0 and the OPBITEN (D5) bit to 0

Triangle Output

The SIN ROM can be bypassed so that the truncated digital output from the NCO is sent to the DAC.
In this case, the output is no longer sinusoidal.
The DAC will produce a 10-bit linear triangular function.
To have a triangle output from the VOUT pin, set the mode (D1) bit = 1.
Note: the SLEEP12 bit must be 0

Table 15. Outputs from the VOUT Pin
*******************************
OPBITEN Bit Mode Bit DIV2 Bit VOUT Pin
0 0 X1 Sinusoid
0 1 X1 Triangle
1 0 0 DAC data MSB/2
1 0 1 DAC data MSB
1 1 X1 Reserved

http://www.analog.com/media/en/technica ... N-1070.pdf

With kind regards
Stephne
Last edited by Stephane Fonteyne on Sun Sep 13, 2015 12:17 pm, edited 1 time in total.
User avatar
RSBasic
Moderator
Moderator
Posts: 1228
Joined: Thu Dec 31, 2009 11:05 pm
Location: Gernsbach (Germany)
Contact:

Re: Control the AD9833 with communication SPI protocol via R

Post by RSBasic »

Can you insert the url again? Thank you
Image
Image
infratec
Always Here
Always Here
Posts: 7575
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Control the AD9833 with communication SPI protocol via R

Post by infratec »

As mentioned in your other thread:

Use a microntroller between, which translates serial commands into SPI.
Or use a LPT port.
A serial port direct needs a lot of hardware around to adjust the voltage levels.

Bernd
Stephane Fonteyne
User
User
Posts: 27
Joined: Sun Sep 06, 2015 2:22 pm

Re: Control the AD9833 with communication SPI protocol via R

Post by Stephane Fonteyne »

infratec wrote:As mentioned in your other thread:

Use a microntroller between, which translates serial commands into SPI.
Or use a LPT port.
A serial port direct needs a lot of hardware around to adjust the voltage levels.

Bernd
Brend

I use the serialport but I have need the general functions for SPI communication as include file (module) and implement in the main application. I may not need use a microcontroller only the PC or laptop.
Is that posiblity without mcu?

I have the PCB with the AD9833 and a levelshifter MAX232

Kind regards
Stephane
infratec
Always Here
Always Here
Posts: 7575
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Control the AD9833 with communication SPI protocol via R

Post by infratec »

Hi,

SPI:
MISO - input
MOSI - output
SCLK - output
SS - output


RS232:
CTS - input
DTR - output
RTS - output
TXD - output

So yes, it is possible.
But you need to adjust the voltages:

SPI has normally 5V levels (or 3.3V)

RS232 is at least -9V and +9V
To adjust the output pins is not a big deal.

Next big disadvantage is the loss off speed.

But Ok, it is possible.
It is only work to implement it.

Bernd
Stephane Fonteyne
User
User
Posts: 27
Joined: Sun Sep 06, 2015 2:22 pm

Re: Control the AD9833 with communication SPI protocol via R

Post by Stephane Fonteyne »

infratec wrote:Hi,

SPI:
MISO - input
MOSI - output
SCLK - output
SS - output


RS232:
CTS - input
DTR - output
RTS - output
TXD - output

So yes, it is possible.
But you need to adjust the voltages:

SPI has normally 5V levels (or 3.3V)

RS232 is at least -9V and +9V
To adjust the output pins is not a big deal.

Next big disadvantage is the loss off speed.

But Ok, it is possible.
It is only work to implement it.

Bernd
Idont' know how I can write the code for SPI communication? When I have the master SPI routines then can I send commands to the AD9833 chip via RS232. For levelshifter use I the MAX232 chip this converts -12 en +12 voltage levels to lower levels I think -5V ...0V .... +5V (squarewave on the scoop)
infratec
Always Here
Always Here
Posts: 7575
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Control the AD9833 with communication SPI protocol via R

Post by infratec »

Hi,

you have the code for the I²C. So where is the big problem to write the code :?:

Anyway, here is the slowest implementation of SPI (but multiple ports possible):

Code: Select all

;
; SPI over RS232
;
; MISO - CTS
; MOSI - DTR
; SCLK - RTS
; SS   - TXD


CompilerIf #PB_Compiler_IsMainFile
  EnableExplicit
CompilerEndIf


Structure SPIoverRS232Structure
  Port.i
  CPOL.i
  CPHA.i
EndStructure




Procedure SPI_Set_SS(*SPI.SPIoverRS232Structure, State)
  If *SPI
    If State
      SetSerialPortStatus(*SPI\Port, #PB_SerialPort_TXD, 0)
    Else
      SetSerialPortStatus(*SPI\Port, #PB_SerialPort_TXD, 1)
    EndIf
  EndIf
EndProcedure


Procedure SPI_Set_SCLK(*SPI.SPIoverRS232Structure, State)
  If *SPI
    If State
      SetSerialPortStatus(*SPI\Port, #PB_SerialPort_RTS, 0)
    Else
      SetSerialPortStatus(*SPI\Port, #PB_SerialPort_RTS, 1)
    EndIf
  EndIf
EndProcedure


Procedure SPI_Set_MOSI(*SPI.SPIoverRS232Structure, State)
  If *SPI
    If State
      SetSerialPortStatus(*SPI\Port, #PB_SerialPort_DTR, 0)
    Else
      SetSerialPortStatus(*SPI\Port, #PB_SerialPort_DTR, 1)
    EndIf
  EndIf
EndProcedure


Procedure.i SPI_Get_MISO(*SPI.SPIoverRS232Structure)
  
  Protected.i Result
  
  If *SPI
    Result = GetSerialPortStatus(*SPI\Port, #PB_SerialPort_CTS)
  EndIf
  
  ProcedureReturn Result
  
EndProcedure


Procedure.i SPI_Open(Port$, CPOL.i=0, CPHA.i=0)
  
  Protected.i Port
  Protected *Result.SPIoverRS232Structure
  
  Port = OpenSerialPort(#PB_Any, Port$, 9600, #PB_SerialPort_NoParity, 8, 1, #PB_SerialPort_NoHandshake, 1, 1)
  If Port
    *Result = AllocateMemory(SizeOf(SPIoverRS232Structure))
    If *Result
      *Result\Port = Port
      *Result\CPOL = CPOL
      *Result\CPHA = CPHA
      
      SPI_Set_SS(*Result, 1)
      If CPOL
        SPI_Set_SCLK(*Result, 1)
      Else
        SPI_Set_SCLK(*Result, 0)
      EndIf
      
    Else
      CloseSerialPort(Port)
    EndIf
  EndIf
  
  ProcedureReturn *Result
  
EndProcedure


Procedure.a SPI_Byte(*SPI.SPIoverRS232Structure, Value.a=0)
  
  Protected.a Result, Mask
  Protected.i i
  
  
  Mask = %10000000
  ;SPI_Set_SS(*SPI, 0)
  If *SPI\CPHA = 0
    SPI_Set_MOSI(*SPI, Value & Mask)
  EndIf
  For i = 0 To 7    
    If *SPI\CPOL = 0
      If *SPI\CPHA = 0
        SPI_Set_SCLK(*SPI, 1)
        If SPI_Get_MISO(*SPI)
          Result | Mask
        EndIf
      Else
        SPI_Set_MOSI(*SPI, Value & Mask)
        SPI_Set_SCLK(*SPI, 1)
      EndIf
    Else
      If *SPI\CPHA = 0
        SPI_Set_SCLK(*SPI, 0)
        If SPI_Get_MISO(*SPI)
          Result | Mask
        EndIf
      Else
        SPI_Set_MOSI(*SPI, Value & Mask)
        SPI_Set_SCLK(*SPI, 0)
      EndIf
    EndIf
    
    If *SPI\CPOL = 0
      If *SPI\CPHA = 0
        SPI_Set_SCLK(*SPI, 0)
      Else
        If SPI_Get_MISO(*SPI)
          Result | Mask
        EndIf
        SPI_Set_SCLK(*SPI, 0)
      EndIf
    Else
      If *SPI\CPHA = 0
        SPI_Set_SCLK(*SPI, 1)
      Else
        If SPI_Get_MISO(*SPI)
          Result | Mask
        EndIf
        SPI_Set_SCLK(*SPI, 1)
      EndIf
    EndIf
    
    Mask >> 1
    
    If *SPI\CPHA = 0
      SPI_Set_MOSI(*SPI, Value & Mask)
    EndIf
    
  Next i
  ;SPI_Set_SS(*SPI, 1)
  
  ProcedureReturn Result
  
EndProcedure


Procedure SPI_Close(*SPI.SPIoverRS232Structure)
  
  If *SPI
    CloseSerialPort(*SPI\Port)
    FreeMemory(*SPI)
    *SPI = #Null
  EndIf
  
EndProcedure




CompilerIf #PB_Compiler_IsMainFile
  
  Define *SPI, Byte.a
  
  *SPI = SPI_Open("COM1", 0, 1)
  If *SPI
    
    SPI_Set_SS(*SPI, 0)
    Byte = SPI_Byte(*SPI, $01)
    Byte = SPI_Byte(*SPI, $00)
    SPI_Set_SS(*SPI, 1)
    Debug RSet(Hex(Byte), 2, "0")
    
    SPI_Close(*SPI)
  EndIf
    
CompilerEndIf
As usual: not tested.
Maybe the polarities are not Ok, since some RS232 pins are inverted.

And I hope, if you have more knowledge, that you give my time back to an other one which needs some help.

Bernd
Last edited by infratec on Sun Sep 13, 2015 8:45 am, edited 1 time in total.
Stephane Fonteyne
User
User
Posts: 27
Joined: Sun Sep 06, 2015 2:22 pm

Re: Control the AD9833 with communication SPI protocol via R

Post by Stephane Fonteyne »

infratec wrote:Hi,

you have the code for the I²C. So where is the big problem to write the code :?:

Anyway, here is the slowest implementation of SPI (but multiple ports possible):

Code: Select all

;
; SPI over RS232
;
; MISO - CTS
; MOSI - DTR
; SCLK - RTS
; SS   - TXD


CompilerIf #PB_Compiler_IsMainFile
  EnableExplicit
CompilerEndIf


Structure SPIoverRS232Structure
  Port.i
  CPOL.i
  CPHA.i
EndStructure




Procedure SPI_Set_SS(*SPI.SPIoverRS232Structure, State)
  If *SPI
    If State
      SetSerialPortStatus(*SPI\Port, #PB_SerialPort_TXD, 0)
    Else
      SetSerialPortStatus(*SPI\Port, #PB_SerialPort_TXD, 1)
    EndIf
  EndIf
EndProcedure


Procedure SPI_Set_SCLK(*SPI.SPIoverRS232Structure, State)
  If *SPI
    If State
      SetSerialPortStatus(*SPI\Port, #PB_SerialPort_RTS, 0)
    Else
      SetSerialPortStatus(*SPI\Port, #PB_SerialPort_RTS, 1)
    EndIf
  EndIf
EndProcedure


Procedure SPI_Set_MOSI(*SPI.SPIoverRS232Structure, State)
  If *SPI
    If State
      SetSerialPortStatus(*SPI\Port, #PB_SerialPort_DTR, 0)
    Else
      SetSerialPortStatus(*SPI\Port, #PB_SerialPort_DTR, 1)
    EndIf
  EndIf
EndProcedure


Procedure.i SPI_Get_MISO(*SPI.SPIoverRS232Structure)
  
  Protected.i Result
  
  If *SPI
    Result = GetSerialPortStatus(*SPI\Port, #PB_SerialPort_CTS)
  EndIf
  
  ProcedureReturn Result
  
EndProcedure


Procedure.i SPI_Open(Port$, CPOL.i=0, CPHA.i=0)
  
  Protected.i Port
  Protected *Result.SPIoverRS232Structure
  
  Port = OpenSerialPort(#PB_Any, Port$, 9600, #PB_SerialPort_NoParity, 8, 1, #PB_SerialPort_NoHandshake, 1, 1)
  If Port
    *Result = AllocateMemory(SizeOf(SPIoverRS232Structure))
    If *Result
      *Result\Port = Port
      *Result\CPOL = CPOL
      *Result\CPHA = CPHA
      
      SPI_Set_SS(*Result, 1)
      If CPOL
        SPI_Set_SCLK(*Result, 1)
      Else
        SPI_Set_SCLK(*Result, 0)
      EndIf
      
    Else
      CloseSerialPort(Port)
    EndIf
  EndIf
  
  ProcedureReturn *Result
  
EndProcedure


Procedure.a SPI_Byte(*SPI.SPIoverRS232Structure, Value.a=0)
  
  Protected.a Result, Mask
  Protected.i i
  
  
  Mask = %10000000
  SPI_Set_SS(*SPI, 0)
  If *SPI\CPHA = 0
    SPI_Set_MOSI(*SPI, Value & Mask)
  EndIf
  For i = 0 To 7    
    If *SPI\CPOL = 0
      If *SPI\CPHA = 0
        SPI_Set_SCLK(*SPI, 1)
        If SPI_Get_MISO(*SPI)
          Result | Mask
        EndIf
      Else
        SPI_Set_MOSI(*SPI, Value & Mask)
        SPI_Set_SCLK(*SPI, 1)
      EndIf
    Else
      If *SPI\CPHA = 0
        SPI_Set_SCLK(*SPI, 0)
        If SPI_Get_MISO(*SPI)
          Result | Mask
        EndIf
      Else
        SPI_Set_MOSI(*SPI, Value & Mask)
        SPI_Set_SCLK(*SPI, 0)
      EndIf
    EndIf
    
    If *SPI\CPOL = 0
      If *SPI\CPHA = 0
        SPI_Set_SCLK(*SPI, 0)
      Else
        If SPI_Get_MISO(*SPI)
          Result | Mask
        EndIf
        SPI_Set_SCLK(*SPI, 0)
      EndIf
    Else
      If *SPI\CPHA = 0
        SPI_Set_SCLK(*SPI, 1)
      Else
        If SPI_Get_MISO(*SPI)
          Result | Mask
        EndIf
        SPI_Set_SCLK(*SPI, 1)
      EndIf
    EndIf
    
    Mask >> 1
    
    If *SPI\CPHA = 0
      SPI_Set_MOSI(*SPI, Value & Mask)
    EndIf
    
  Next i
  SPI_Set_SS(*SPI, 1)
  
  ProcedureReturn Result
  
EndProcedure


Procedure SPI_Close(*SPI.SPIoverRS232Structure)
  
  If *SPI
    CloseSerialPort(*SPI\Port)
    FreeMemory(*SPI)
    *SPI = #Null
  EndIf
  
EndProcedure




CompilerIf #PB_Compiler_IsMainFile
  
  Define *SPI, Byte.a
  
  *SPI = SPI_Open("COM1")
  If *SPI
    
    Byte = SPI_Byte(*SPI, $AA)
    Debug RSet(Hex(Byte), 2, "0")
    
    SPI_Close(*SPI)
  EndIf
    
CompilerEndIf
As usual: not tested.
Maybe the polarities are not Ok, since some RS232 pins are inverted.

And I hope, if you have more knowledge, that you give my time back to an other one which needs some help.

Bernd
This is a short example using serialport with SPI. The chip is a MAX187
http://datasheets.maximintegrated.com/e ... MAX189.pdf

Code: Select all

#VREF         = 5.09        ; Reference Voltage
#ADC_12_BIT   = 4096

result.l = OpenSerialPort(#PB_Any,"COM2:",9600,#PB_SerialPort_NoParity,8,1,#PB_SerialPort_NoHandshake,1024,1024)

SetSerialPortStatus(0,#PB_SerialPort_DTR,0)   ; CS   goes high
SetSerialPortStatus(0,#PB_SerialPort_RTS,0)   ; SCLK goes high
SetSerialPortStatus(0,#PB_SerialPort_RTS,1)   ; SCLK goes low
SetSerialPortStatus(0,#PB_SerialPort_DTR,1)   ; CS   goes low conv starts

Repeat(GetSerialPortStatus(0,#PB_SerialPort_CTS) = #True)
  ;Waiting while conversion is in progress  
Until

;Processing 12 SCLK pulses
For i.i = 0 To 12
  ; SCLK goes high
  SetSerialPortStatus(0,#PB_SerialPort_RTS,0) 
  ; SCLK goes low
  SetSerialPortStatus(0,#PB_SerialPort_RTS,1)
  ; Reading appropriate bit into variable b
  If(GetSerialPortStatus(0,#PB_SerialPort_CTS) = #False) 
    k |= b
  End If
      
  ;shift bits of the variable b right For checking the Next bit
   b = b >> 1
Next
  
; Conversion is done. so CS line goes high
SetSerialPortStatus(0,#PB_SerialPort_DTR,0)

;Close the serialport
CloseSerialPort(0)

;Now the variable k contains the binary result of the conversion.  
;The value of k must be transformed into float value which will be  
;saved in variable total   
Protected binRes.i
Protected total.f
Protected temp.f
Protected sres.s

binRes = k
total = ConvertDouble(binRes)

;Calculating the final result
total = #VREF / #ADC_12_BIT * total      ; 12 bits ADC

; Output data on to screen
temp = total * 100.0
sres = formatstring("00.#")
Stephane Fonteyne
User
User
Posts: 27
Joined: Sun Sep 06, 2015 2:22 pm

Re: Control the AD9833 with communication SPI protocol via R

Post by Stephane Fonteyne »

Stephane Fonteyne wrote:
infratec wrote:Hi,

SPI:
MISO - input
MOSI - output
SCLK - output
SS - output


RS232:
CTS - input
DTR - output
RTS - output
TXD - output

So yes, it is possible.
But you need to adjust the voltages:

SPI has normally 5V levels (or 3.3V)

RS232 is at least -9V and +9V
To adjust the output pins is not a big deal.

Next big disadvantage is the loss off speed.

But Ok, it is possible.
It is only work to implement it.

Bernd
Idont' know how I can write the code for SPI communication? When I have the master SPI routines then can I send commands to the AD9833 chip via RS232. For levelshifter use I the MAX232 chip this converts -12 en +12 voltage levels to lower levels I think -5V ...0V .... +5V (squarewave on the scoop)
The Serial Peripheral Interface (SPI) circuit is a synchronous serial
data link that is standard across many Motorola microprocessors and other
peripheral chips. It provides support for a high bandwidth (1 megabaud)
network connection amongst CPUs and other devices supporting the SPI.

To implement this without special hardware on a PC, you'll have to "bit
bang" it. While this could be done using CTS, RTS and DTR on the PC, it
would require some level shifting hardware to convert to/from RS232 signal
levels.Really the parallel port would be much easier.

I'd consider writing a DLL in C and calling that. Better still, grab a
microcontroller with a built in full speed hardware supported SPI interface
as well as a UART, and stick that on the
serial port.
infratec
Always Here
Always Here
Posts: 7575
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Control the AD9833 with communication SPI protocol via R

Post by infratec »

Hi,

I changed my SPI stuff above to be able to transmit more than one byte with SS low.
The demo at the end should do a reset on the AD9833.
Stephane Fonteyne
User
User
Posts: 27
Joined: Sun Sep 06, 2015 2:22 pm

Re: Control the AD9833 with communication SPI protocol via R

Post by Stephane Fonteyne »

infratec wrote:Hi,

I changed my SPI stuff above to be able to transmit more than one byte with SS low.
The demo at the end should do a reset on the AD9833.
Pseudo example:

fout = 400Hz ; fMCLK = 25 MHz

Freq_Reg = (fout * 2 ^ 28) / fMCLK ==> (400Hz * 2 ^ 28) / 25Mhz = 4295 (dec) = 0x10C7 (hex) = 0001 0000 1100 0111

Send control or register word : Send_SPI(0x2100)
Send data word to Freq Register 0 LSB : Send_SPI(0x50C7)
Send data word to Freq Register 0 MSB : Send_SPI(0x4000)
Send data word to Phase Register 0 : Send_SPI(0xC000)
Send data exit reset : Send_SPI(0x2000)

How can I program the DDS chip in PureBasic ?

I especially like the frequency, phase and golvormen can set up and can make them visible in a GUI application .

What is the best opportunity SPI directly over the serial port or
piece firmware communicates via SPI with the AD9833 chip. And that the PC can read the results and can send data to the microcontroller ?

This is my try with your SPI as include file
==========================

Code: Select all


;
; SPI over RS232
;
; MISO - CTS
; MOSI - DTR
; SCLK - RTS
; SS   - TXD

IncludeFile "rs232_spi.pbi"

Define *SPI, Byte.a

*SPI = SPI_Open("COM1", 0, 1)

If(*SPI)
  SPI_Set_SS(*SPI, 0)
  ;0x2100—Control Register
  Byte = SPI_Byte(*SPI, $00)
  Byte = SPI_Byte(*SPI, $21)
  
  ;0x50C7—Frequency Register 0 LSB
  Byte = SPI_Byte(*SPI, $C7)
  Byte = SPI_Byte(*SPI, $50)
  
  ;0x4000—Frequency Register 0 MSB
  Byte = SPI_Byte(*SPI, $00)
  Byte = SPI_Byte(*SPI, $40)
  
  ;0xC000—Phase Register 0
  Byte = SPI_Byte(*SPI, $00)
  Byte = SPI_Byte(*SPI, $C0)
  
  ;0x2000—Exit Reset
  Byte = SPI_Byte(*SPI, $00)
  Byte = SPI_Byte(*SPI, $20)
  
  SPI_Set_SS(*SPI, 1)
  
  ;Display the results
  Debug RSet(Hex(Byte), 2, "0")
  SPI_Close(*SPI)
EndIf
My ask is that the correct order to send the bytes?

Kind regards
Stephane
Last edited by Stephane Fonteyne on Sun Sep 13, 2015 8:14 pm, edited 2 times in total.
infratec
Always Here
Always Here
Posts: 7575
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Control the AD9833 with communication SPI protocol via R

Post by infratec »

Hi,

I don't know what I should do with you...

I gave you all to do this task.
So simply do it.
Or if something is not working, than tell it and I'll try to fix it.

But if you are not able to use the code which I wrote to todo what you need,
than I don't know what I can do for you. Really.

Or give someone the order to do this task, because this has nothing todo with 'coding questions',
this is something for 'doing the coding for me'.

Bernd
Stephane Fonteyne
User
User
Posts: 27
Joined: Sun Sep 06, 2015 2:22 pm

Re: Control the AD9833 with communication SPI protocol via R

Post by Stephane Fonteyne »

infratec wrote:Hi,

I don't know what I should do with you...

I gave you all to do this task.
So simply do it.
Or if something is not working, than tell it and I'll try to fix it.

But if you are not able to use the code which I wrote to todo what you need,
than I don't know what I can do for you. Really.

Or give someone the order to do this task, because this has nothing todo with 'coding questions',
this is something for 'doing the coding for me'.

Bernd
Hi Berndt,

Do you have some experience in programming of firmware for the PIC microcontroller PIC18F2550 .
Since I did some code . Can I post once you know where I want to go

Just read the datasheet and all studies how the chip works and how to program it. First I 'm a simple example writeable with you SPI routines over the serial port . What can I best do a quick console application , or as a GUI application ?

What 's your preference how I best a simple demo program ?

Can I use your code code used and compiled as DLL library. Is this code ready to compile it for a DLL library. You can named it with rs232_spi.dll

This the code in DLL form:

Code: Select all

;
; SPI over RS232
;
; MISO - CTS
; MOSI - DTR
; SCLK - RTS
; SS   - TXD


;CompilerIf #PB_Compiler_IsMainFile
;  EnableExplicit
;CompilerEndIf


Structure SPIoverRS232Structure
  Port.i
  CPOL.i
  CPHA.i
EndStructure

ProcedureDLL SPI_Set_SS(*SPI.SPIoverRS232Structure, State)
  If *SPI
    If State
      SetSerialPortStatus(*SPI\Port, #PB_SerialPort_TXD, 0)
    Else
      SetSerialPortStatus(*SPI\Port, #PB_SerialPort_TXD, 1)
    EndIf
  EndIf
EndProcedure


ProcedureDLL SPI_Set_SCLK(*SPI.SPIoverRS232Structure, State)
  If *SPI
    If State
      SetSerialPortStatus(*SPI\Port, #PB_SerialPort_RTS, 0)
    Else
      SetSerialPortStatus(*SPI\Port, #PB_SerialPort_RTS, 1)
    EndIf
  EndIf
EndProcedure


ProcedureDLL SPI_Set_MOSI(*SPI.SPIoverRS232Structure, State)
  If *SPI
    If State
      SetSerialPortStatus(*SPI\Port, #PB_SerialPort_DTR, 0)
    Else
      SetSerialPortStatus(*SPI\Port, #PB_SerialPort_DTR, 1)
    EndIf
  EndIf
EndProcedure


ProcedureDLL.i SPI_Get_MISO(*SPI.SPIoverRS232Structure)
  
  Protected.i Result
  
  If *SPI
    Result = GetSerialPortStatus(*SPI\Port, #PB_SerialPort_CTS)
  EndIf
  
  ProcedureReturn Result
  
EndProcedure


ProcedureDLL.i SPI_Open(Port$, CPOL.i=0, CPHA.i=0)
  
  Protected.i Port
  Protected *Result.SPIoverRS232Structure
  
  Port = OpenSerialPort(#PB_Any, Port$, 9600, #PB_SerialPort_NoParity, 8, 1, #PB_SerialPort_NoHandshake, 1, 1)
  If Port
    *Result = AllocateMemory(SizeOf(SPIoverRS232Structure))
    If *Result
      *Result\Port = Port
      *Result\CPOL = CPOL
      *Result\CPHA = CPHA
      
      SPI_Set_SS(*Result, 1)
      If CPOL
        SPI_Set_SCLK(*Result, 1)
      Else
        SPI_Set_SCLK(*Result, 0)
      EndIf
      
    Else
      CloseSerialPort(Port)
    EndIf
  EndIf
  
  ProcedureReturn *Result
  
EndProcedure


ProcedureDLL.a SPI_Byte(*SPI.SPIoverRS232Structure, Value.a=0)
  
  Protected.a Result, Mask
  Protected.i i
  
  
  Mask = %10000000
  ;SPI_Set_SS(*SPI, 0)
  If *SPI\CPHA = 0
    SPI_Set_MOSI(*SPI, Value & Mask)
  EndIf
  For i = 0 To 7    
    If *SPI\CPOL = 0
      If *SPI\CPHA = 0
        SPI_Set_SCLK(*SPI, 1)
        If SPI_Get_MISO(*SPI)
          Result | Mask
        EndIf
      Else
        SPI_Set_MOSI(*SPI, Value & Mask)
        SPI_Set_SCLK(*SPI, 1)
      EndIf
    Else
      If *SPI\CPHA = 0
        SPI_Set_SCLK(*SPI, 0)
        If SPI_Get_MISO(*SPI)
          Result | Mask
        EndIf
      Else
        SPI_Set_MOSI(*SPI, Value & Mask)
        SPI_Set_SCLK(*SPI, 0)
      EndIf
    EndIf
    
    If *SPI\CPOL = 0
      If *SPI\CPHA = 0
        SPI_Set_SCLK(*SPI, 0)
      Else
        If SPI_Get_MISO(*SPI)
          Result | Mask
        EndIf
        SPI_Set_SCLK(*SPI, 0)
      EndIf
    Else
      If *SPI\CPHA = 0
        SPI_Set_SCLK(*SPI, 1)
      Else
        If SPI_Get_MISO(*SPI)
          Result | Mask
        EndIf
        SPI_Set_SCLK(*SPI, 1)
      EndIf
    EndIf
    
    Mask >> 1
    
    If *SPI\CPHA = 0
      SPI_Set_MOSI(*SPI, Value & Mask)
    EndIf
    
  Next i
  ;SPI_Set_SS(*SPI, 1)
  
  ProcedureReturn Result
  
EndProcedure


ProcedureDLL SPI_Close(*SPI.SPIoverRS232Structure)
  
  If *SPI
    CloseSerialPort(*SPI\Port)
    FreeMemory(*SPI)
    *SPI = #Null
  EndIf
  
EndProcedure

;CompilerIf #PB_Compiler_IsMainFile
;  
;  Define *SPI, Byte.a
;  
;  *SPI = SPI_Open("COM1", 0, 1)
;  If *SPI
;    
;    SPI_Set_SS(*SPI, 0)
;    Byte = SPI_Byte(*SPI, $01)
;    Byte = SPI_Byte(*SPI, $00)
;    SPI_Set_SS(*SPI, 1)
;    Debug RSet(Hex(Byte), 2, "0")
;    
;    SPI_Close(*SPI)
;  EndIf
;    
;CompilerEndIf
Post Reply