![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
SvenBraun
Joined: 19 Mar 2016 Posts: 29
|
Software SPI |
Posted: Wed Apr 06, 2016 8:11 pm |
|
|
I will preface this question by saying I've turned to my colleagues, countless searching online, and reading my datasheets and the CCS manual, but I haven't found what I'm looking for.
----
System information:
uC: PIC18F4455
DDS: AD9102
I am still new to SPI, and unfortunately, most of the resources I'm seeing are for hardware SPI. While the PIC18F series has hardware SPI, I can't use it (or it's very tricky to use it) in conjunction with UART (because there is a shared pin between UART and SPI), which is a requirement in my system.
So, because CCS supports software SPI, I have turned to that to solve my issue.
Unfortunately, a majority of people I work with do not use external DDS's, and even if they have, nobody has used software SPI in their system. So I'm more or less going in blind.
I have my Trigger, Reset, Chip Select, DI, DO, and SPI clock hooked up.
Here are my declarations for UART and SPI capabilities:
Code: | #use rs232(baud=115200, xmit=PIN_C6, rcv=PIN_C7)
#use SPI(MASTER, MODE=0, BAUD=115200, CLK=PIN_E0, DI=PIN_E1, DO=PIN_E2, BITS=16, NOINIT)
|
I am initiating transfer of SPI through the following method:
Code: |
if(!isEmpty(&DDS_instructions))
{
delay_ms(5);
// If there are elements in the queue, remove them.
while(!isEmpty(&DDS_instructions))
{
delay_ms(20);
a = pop(&DDS_instructions); // First pop should always be the address
delay_ms(20);
e = pop(&DDS_instructions); // Second pop should always be the data
sendSPI(a,e);
delay_ms(20);
}
// When all instructions are sent, update the SPI settings on the DDS
sendSPI(RAMUPDATE, UPDATESPI);
turnOnTRIGGER;
} |
Here are my main functions for sending SPI:
ADDRESS and ELEMENT are both int16_t type.
Code: |
void sendSPI(ADDRESS addrX, ELEMENT dataX)
{
// Configure for transfer
turnOnCS; // Start transfer (Active low)
// Transferring
spi_send(addrX); // Send address first
spi_send(dataX); // Send data (see note above)
// Reconfigure to end transfer
//-- RAMUPDATE bit can be placed here to finish the transfer to shadow registers
// but the transfers happen automatically when the pattern generator is off.
turnOffCS; // End transfer
}
void spi_send(ELEMENT data)
{
int i = 15;
while(i+1 > 0)
{
output_high(PIN_E0); // High during transfer
spi_xfer( ((data>>i)&0x1) );
i--;
output_low(PIN_E0); // Low after sending
}
} |
My output so far is producing a sine wave through the DDS's differential current output at 60 Hz. I'm assuming that since I've been changing the desired frequency in my code, yet it's maintained 60 Hz, that I'm not programming it correctly.
I've looked at the example codes, but the one provided in PICC/Examples is for Hardware implementation of SPI.
Last edited by SvenBraun on Wed Apr 06, 2016 10:01 pm; edited 1 time in total |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Apr 06, 2016 9:31 pm |
|
|
What are you doing here ?
Quote: | void spi_send(ELEMENT data)
{
int i = 15;
while(i+1 > 0)
{
output_high(PIN_E0); // High during transfer
spi_xfer( ((data>>i)&0x1) );
i--;
output_low(PIN_E0); // Low after sending
}
} |
In your statement below, you specify 16 bit transfers.
Quote: | #use SPI(MASTER, MODE=0, BAUD=115200, CLK=PIN_E0, DI=PIN_E1, DO=PIN_E2, BITS=16, NOINIT) |
This means spi_xfer() will automatically handle the transmission of 16 bits
of data. All you need is one line of code to transmit all 16 bits.
|
|
![](templates/subSilver/images/spacer.gif) |
SvenBraun
Joined: 19 Mar 2016 Posts: 29
|
|
Posted: Wed Apr 06, 2016 9:58 pm |
|
|
Good point.
My main issue is not understanding how SCK interacts with the software SPI. In the datasheets, they illustrate the writing process with sending one bit per clock cycle.
In my original version, I sent it all at once, and that second SPI function wasn't involved. When I realized my clock wasn't changing, I added that function in, so I could send one bit at a time, while manually changing the clock line.
I have modified that BITS=16 to BITS=1 in my program.
EDIT: I accidentally omitted the calling function from the method and sendSPI. I updated the original post to include where that was. |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Apr 06, 2016 11:25 pm |
|
|
Quote: |
When I realized my clock wasn't changing, I added that function in, so I
could send one bit at a time, while manually changing the clock line.
I have modified that BITS=16 to BITS=1 in my program.
|
If the SPI clock is not changing, then something is very wrong.
You should not do a work-around. You should trouble-shoot and
fix the missing clock problem.
Do that by removing all higher level code and reducing the
program down so it sends 16-bits with the spi_xfer() function,
and that's all it does. Don't connect an SPI slave device to
the SCK pin. Just watch it with an oscilloscope. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19382
|
|
Posted: Thu Apr 07, 2016 2:05 am |
|
|
Some comments:
In the CCS examples, the SPI _slave_ uses hardware, the SPI _master_ uses hardware or software, according to the pins you use. This is documented in the comments.
NOINIT, only applies to a hardware port.
Then have you disabled the SPP port (PSP)?. Old 'rule' with the PIC, always make sure every other peripheral on the pins you are trying to use is disabled. Your pins are all used for SPP functions. Quite a few peripherals do default to disabled, but many others default to enabled.
Why on earth are you trying to use 115200bps?. Binary serial values have no advantage for this. Suggest something simple that relates to your CPU clock rate like 200000bps.
You don't show what values you are actually sending, but since the pattern generator is off, nothing will be output. Then also nothing will be output, till you change the start and end address used by the pattern generator.
For a while just forget the chip you are trying to talk to. Do a simple piece of code initialising the chip, and with the #USE SPI, and have this loop sending words out the SPI port. So something like:
Code: |
//Your chip setup and clock
:
#use rs232(baud=115200, xmit=PIN_C6, rcv=PIN_C7)
#use SPI(MASTER, MODE=0, BAUD=200000, CLK=PIN_E0, DI=PIN_E1, DO=PIN_E2, BITS=16)
void main(void)
{
int16 val;
output_high(CS);
setup_ccp1(CCP_OFF);
setup_ccp2(CCP_OFF);
setup_psp(PSP_DISABLED);
setup_comparator(NC_NC_NC_NC);
setup_adc(ADC_OFF);
setup_adc_ports(NO_ANALOGS);
while(TRUE)
{
for (val=0;val<256;val++)
{
output_low(CS); //whatever pin you want
spi_xfer(val);
output_high(CS);
delay_us(50);
}
}
}
|
Sync your scope on CS, and look at the clock and data.
You should see the CS drop, then 8 clocks with the data line held low, then 8 clocks with the value 'counting' from 0 to 255, then CS going high, then a short pause and the cycle starting again.
Key thing with debugging is to always step back and attack _just_ the core problem. Forget about your chip and everything, till you know how to drive the SPI. Only then start to attack the bigger problems.... |
|
![](templates/subSilver/images/spacer.gif) |
SvenBraun
Joined: 19 Mar 2016 Posts: 29
|
|
Posted: Thu Apr 07, 2016 11:52 am |
|
|
Thank you to both of you!
I noticed myself getting flustered with the issue, and knew I had to step back to look at the problem again, but I really should have stepped back to the core of SPI, which I should've done in the first place.
I've played around with the code that Ttelmah posted, and saw exactly what I was looking for: with the oscilloscope, I noticed my clock going for 16 bits, and then going low. My data line also had data being transferred. (I wish this was an example in the PICC examples library, for how simple it is.)
I modified it to 8-bit transfer, and the oscilloscope output matched what I expected.
I do have one more question:
Ttelmah, you mentioned that the general rule is to disable unused peripherals, because the pins are all used for SSP functions. (Something I didn't know, but am now writing down to never forget.)
To either of you:
If I was going to add, for example, an ADC component to my system, can there be potential issues with overlapping data from the SSP? Or are peripherals that are set-up to specific pins become dedicated to that peripheral? |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19382
|
|
Posted: Thu Apr 07, 2016 11:59 am |
|
|
You need to make sure that in the setup_adc_ports command, the analog channels corresponding to these bits are not enabled. Some peripherals use specific pins, others (like the ADC), have them selectable.
If you use a stream name for the #use spi, you can change the transfer length 'on the fly'. If you look at the spi_xfer command, when a stream name is used, you can use the command like:
spi_xfer(STREAM_NAME, data_to_send, number_of_bits_to_send); |
|
![](templates/subSilver/images/spacer.gif) |
SvenBraun
Joined: 19 Mar 2016 Posts: 29
|
|
Posted: Thu Apr 07, 2016 12:05 pm |
|
|
So using peripherals that have more than one channel, as long as you do something like:
Code: | setup_adc_ports(AN0); |
Only the first analog channel will be enabled, with the other channels remaining disabled like in:
Code: | setup_adc_ports(NO_ANALOGS); |
|
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19382
|
|
Posted: Thu Apr 07, 2016 2:14 pm |
|
|
Exactly. |
|
![](templates/subSilver/images/spacer.gif) |
SvenBraun
Joined: 19 Mar 2016 Posts: 29
|
|
Posted: Fri Apr 08, 2016 12:33 pm |
|
|
Perfect, thank you! Now I can focus on programming the DDS. |
|
![](templates/subSilver/images/spacer.gif) |
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Sat Apr 09, 2016 7:16 pm |
|
|
After reading the data sheet for the AD9102
i think you are going to have much education and entertainment
ahead of you in programming a driver using
code like this example.
spi_xfer( ((data>>i)&0x1) );
have a closer look at the number of
bits transmitted for various different commands
while /CS is low. |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Apr 09, 2016 7:38 pm |
|
|
That's what we were pointing out to him. But he never said for certain
if he had fixed it. |
|
![](templates/subSilver/images/spacer.gif) |
SvenBraun
Joined: 19 Mar 2016 Posts: 29
|
|
Posted: Sat Apr 09, 2016 8:30 pm |
|
|
asmboy wrote: | After reading the data sheet for the AD9102
i think you are going to have much education and entertainment
ahead of you in programming a driver using
code like this example.
spi_xfer( ((data>>i)&0x1) );
have a closer look at the number of
bits transmitted for various different commands
while /CS is low. |
I don't quite understand what you mean.
Following PCM and Ttelmah's advice, I stepped back to a simpler program, and reverted a lot of those changes.
After modification, my code changed back to 16-bit spi_xfers; one for address, and one for data.
The datasheet for AD9102 mentions that the addresses and the data themselves are 16-bits each, for a total of 32 bits.
I have tried modifying my spi_xfers to 32 bits (and sending the command + data together), but I didn't see much change. |
|
![](templates/subSilver/images/spacer.gif) |
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Sat Apr 09, 2016 10:04 pm |
|
|
The data sheet issue i refer to is the single or double command possibility.
Without knowing what problem you are still having
the whatever that "has not changed"
and
without seeing your best shot at the code.
i don't know what can be done to help. |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Apr 09, 2016 10:32 pm |
|
|
I'm pretty sure he has gotten rid of his faulty spi_send() routine and
replaced it with a simple spi_xfer() line, but he doesn't know how to tell you this. |
|
![](templates/subSilver/images/spacer.gif) |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|