Menu

I2C controlling AD9850 DDS

2017-11-03
2017-11-03
  • Harley Burton

    Harley Burton - 2017-11-03

    I am trying to use a PIC16F690 to control an Analog Devices AD9850. I have read all the documentation many times concerning the I2C to control the AD9850. I have the control words worked out with no translation, etc. So my question is this; does the I2C routines send the data out MSB first, or LSB first? Additionally, is there any translation of the data or is it just sent out straight? In I2C, the address is shifted left one bit and typically a 0 or 1 added at the end of the address to indicate whether the operation is a read or write. While I don't see that in the AD9850 datasheet, so I'm wondering if the I2C routines in Great Cow Basic do any address or other data translation.

    Please help!

    Thanks,
    Harley Burton
    N5BFB

     
  • mmotte

    mmotte - 2017-11-04

    Harley,
    Looking at the AD9850 datasheet for serial control the LSB (b0)goes out first. followed by the other 39 bits. The bitsare sent to Pin 25 (D7) data input and are shifted in on the rising edge of the w_clk, Pin 7. after 40 bits are shifted in then FQ_UD Pin 8 is told to rise which loads the new info into frequency and control. This also resets t bit pointer back to b0 .

    This is not I2C protocol nor SPI . The PIC16F690 does have a Synchronous Serial Port (SSP) module but it shifts the msb out first.

    There is no addressing issues on the AD9850 because you are directly controlling the 3 pins for input not through a common bus structure with addresses or chip selects.

    So this leads to the need for a software solution to shift the 40 bits out , toggle the clock, and tell it to load.

    I have a couple of the AD9850 boards but never did anything with them.

    GL
    73
    Mike W9YS

     
  • Harley Burton

    Harley Burton - 2017-11-04

    Mike,
    Thanks. I guess since it only had the one clock and data lines, I assumed it was an I2C interface...duh. I should have read it more thoroughly and it has been a real challenge to me to make it all come together. I didn one as a parallel interface many years ago but it has been a long time. The PIC16F690 has a synchronous serial port and it looks like that is exactly what I am looking for. You really cleared it up to me.
    This site looks to be very good and I am looking forward to working with all of you. When I get a load routine working, I'll be sure and post it for others.
    Thanks again,
    Harley
    N5BFB
    73's

     
  • joe rocci

    joe rocci - 2017-11-04

    Harley,

    I did this years ago in PIcBasicPro. PBP has a function called SHIFTOUT that does this but my method is actually faster and produces more compact object code

    Herei s the section of code that sends the 40 bits of data to the AD9850. It's written as a 'bit bang' equivalent of PicBasicPro's SHIFTOUT, but you should get the idea and easily translate it to GCB. You'll have to create a 5 byte freq_byte () array (40 bits) with the binary frequency in the 1st 4 bytes and the control byte in the 5th byte. You'll also have to define port bits for spi_data, spi_clk and spi_latch.

    Joe

    '***********
    '   SUBROUTINES
    '***********

    'Update the DDS frequency

    Update_dds:
    For i = 0 To 3
        freq_byte = freq(i) 'Send the 4 frequency bytes
        Gosub send_spi
    Next i
    freq_byte = $00 'Send the control byte
    Gosub send_spi
    spi_latch_dds = 1 'Toggle the DDS Latch line after all 5 bytes
    spi_latch_dds = 0 'have been sent.
    Return
    '***********
    ' Clocks a single byte out the SPI port
    ' This 'brute force' single-byte SPI transmit routine is 3-4 times faster than
    ' SHIFTOUT and it actually compiles to fewer bytes of object code

    send_spi:
    spi_data = freq_byte.0 'Iterate through all 8 bits of the byte;
    spi_clk = 1 'set the SPI_DATA line to the state of that
    spi_clk = 0 'bit, and toggle the SPI_CLK line.
    spi_data = freq_byte.1
    spi_clk = 1
    spi_clk = 0
    spi_data = freq_byte.2
    spi_clk = 1
    spi_clk = 0
    spi_data = freq_byte.3
    spi_clk = 1
    spi_clk = 0
    spi_data = freq_byte.4
    spi_clk = 1
    spi_clk = 0
    spi_data = freq_byte.5
    spi_clk = 1
    spi_clk = 0
    spi_data = freq_byte.6
    spi_clk = 1
    spi_clk = 0
    spi_data = freq_byte.7
    spi_clk = 1
    spi_clk = 0
    Return
    '************

     

    Last edit: joe rocci 2017-11-05
  • mmotte

    mmotte - 2017-11-05

    Harley,

    The synchronous serial serial port hardware sends the MSB first, so you would have to swap the bits of the byte before sending. This could be done.

    OR

    Joe has a good solution above, just bitbanging the bits out.

    The port's Pins would be defined at the beginning of the program like:

    #define spi_data  PortC.5
    #define spi_clk   PortC.4
    #define spi_latch_dds PortC.3
    
    dir spi_data out
    dir spi_clk  out
    dir spi_latch_dds out
    
    spi_dat = 0
    spi_clk = 0
    spi_latch_dds = 0
    

    Gl
    73
    Mike w9ys

     
  • joe rocci

    joe rocci - 2017-11-05

    Harley
    I should have included these test constants in case you want to try it out

    'Set DDS to 7.000 MHz
    Freq(0) = $1F 'LSB of frequency
    Freq(1) = $85
    Freq(2) = $EB
    Freq(3) = $11 'MSB of frequency
    gosub update_dds

     

    Last edit: joe rocci 2017-11-05
  • Harley Burton

    Harley Burton - 2017-11-06

    Thanks all. I have been looking at using the built in serial port in the synchronous mode. it should be exactly what I need if I can figure out how to use it. It accepts the byte to be sent out with easy to use (I hope) double buffering and the exact number of clocks for each word. It appears there are also no interruptions in the datastream and clock stream when it is working properly. So, now I have to find out how to set it up. Not enough infformation in the GCB reference manual. Anybody who knows how, that would be the best method. Otherwise, I'll probably fix above and use it. I have the bytes reversed but in serial mode, it sends the 0x00 LAST, not first as your example. The synchronous serial mode though would be my preference. There may actually be less code. For what I have to do, I might even be able to fit it into something like a PIC10F322 or something like that. That would really be great.

    Advise?

    Harley
    N5BFB
    73's to all.

     
    • joe rocci

      joe rocci - 2017-11-06

      Harley
      My. code sends the control byte last and and all other bytes in correct order. One other advantage of this method is that it works on any port of any PIC

       
  • Harley Burton

    Harley Burton - 2017-11-06

    Sorry, I read it wrong. Thanks for correcting me.

    Harley

     
  • Harley Burton

    Harley Burton - 2017-11-07

    I had a thought. If I'm correct, the serial port wouldn't know whether it was in Synchronous or Asynchronous mode when setting the baud rate. So if I used the asynchronous baud rate setup SER1_BAUD 128000 it should set up the port for the highest data rate which then could use the same for synchronous mode at that same speed. Do you agree?

    I also copied setting the proper bits from someone else's routine in assembler. Do you concur with this as well?

    ;Set SYNC On
    bsf TXSTA,SYNC
    ;Set CSRC On
    bsf TXSTA, CSRC
    ;Set SREN Off
    bcf TXSTA, SREN
    ;Set CREN Off
    bcf RCSTA, CREN
    ;Set SPEN On
    bsf RCSTA,SPEN
    ;Set SCKP On
    bsf TXSTA, SCKP
    ;Set TXEN On
    bsf TXSTA,TXEN
    banksel STATUS

    I think this is what it should look like. Do you agree or have any other comments.

    Thanks,

    Harley
    N5BFB
    73's

     
  • William Roth

    William Roth - 2017-11-07

    While I cannot speak to the method of communication with the AD9850 as I have not studied the protocol in the datasheet, I can suggest some other stuff.

    GCB will create optimized ASM for you, so there is generally no need to use inline ASM in the source code. For example this BASIC code....

    Set SYNC On
    Set CSRC On
    Set SREN Off
    Set CREN Off
    Set SPEN On
    Set SCKP On
    Set TXEN On
    STATUS = 0
    .
    

    Will generate this ASM code. ( comments removed)

    banksel TXSTA
    bsf TXSTA,SYNC
    bsf TXSTA,CSRC
    
    banksel RCSTA
    bcf RCSTA,SREN
    bcf RCSTA,CREN
    bsf RCSTA,SPEN
    
    banksel BAUDCTL
    bsf BAUDCTL,SCKP
    bsf TXSTA,TXEN
    clrf STATUS
    

    Note: GCB will not accept "banksel" as the GCB compiler will automatically generate a "banksel" to select the correct bank for the register being written or read.

    There is no need to use "banksel status" as the status register is available to all 4 register banks. You could simply use STATUS = 0 which will generate "clrf status" to select bank 0 if that is the purpose of "banksel status".

    William

     

Log in to post a comment.