|
|
View previous topic :: View next topic |
Author |
Message |
SkeeterHawk
Joined: 16 Oct 2010 Posts: 31 Location: Florissant, CO
|
Newbie question on program flow |
Posted: Sat Oct 16, 2010 2:29 am |
|
|
Hey everyone. I am new to writing my own C code, but am really enjoying the CCS compiler. I have found answers to my other questions on this forum, but I am missing something very fundamental and I would sincerely appreciate your input. This is as simple as it gets. I am just trying to create a full-scale triangle wave on a 12-bit DAC. I have tried it two different ways and both times the same thing occurs...only the first function or loop called will be executed and the second ignored. Here is what I thought was the linear version that I wrote first:
Code: | void main()
{
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_CLOCK_DIV_2);
setup_psp(PSP_DISABLED);
setup_spi(SPI_MASTER|SPI_L_TO_H|SPI_CLK_DIV_4);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
// setup_spi(spi_master); // Set up SPI master mode
output_low(PIN_C0); // Pull the DAC chip select low to enable the communication
while(1)
{
int16 number; // Declare the 16-bit integer number
for(number=0; number<1023; number++)
{
spi_write(number); // Output the current count to the DAC
output_low(PIN_C1); // Strobe the load DAC input
delay_ms(250); // Delay just a moment
output_high(PIN_C1); // Bring it high again
}
for(number=1023; number>0; number--)
{
spi_write(number); // Output the current count to the DAC
output_low(PIN_C1); // Strobe the load DAC input
delay_ms(250); // Delay just a moment
output_high(PIN_C1); // Bring it high again
}
}
} |
This only allows the DAC to count up and then starts over. Trying to be smarter than your average bear, and prove to myself that I am gaining an understanding of writing my own programs, I changed it to use functions instead as follows:
Code: | void count_up()
{
int16 number; // Declare the 16-bit integer number
for(number=0; number<1023; number++)
{
spi_write(number); // Output the current count to the DAC
output_low(PIN_C1); // Strobe the load DAC input
delay_ms(250); // Delay just a moment
output_high(PIN_C1); // Bring it high again
}
}
void count_down()
{
int16 number; // Declare the 16-bit integer number
for(number=1023; number>0; number--)
{
spi_write(number); // Output the current count to the DAC
output_low(PIN_C1); // Strobe the load DAC input
delay_ms(250); // Delay just a moment
output_high(PIN_C1); // Bring it high again
}
}
void main()
{
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_CLOCK_DIV_2);
setup_psp(PSP_DISABLED);
setup_spi(SPI_MASTER|SPI_L_TO_H|SPI_CLK_DIV_4);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
// setup_spi(spi_master); // Set up SPI master mode
output_low(PIN_C0); // Pull the DAC chip select low to enable the communication
while(1)
{
count_down();
count_up();
}
} |
This would only allow the DAC to count down and then start over again.
As I said, I am obviously missing something very fundamental. I am only including the main() function as I think that is all you really need. Let me know if I am leaving out something, but I doubt it. This is some kind of bone-head mistake I am sure.
Thanks SO MUCH for your input. This will greatly help my sanity to understand why this isn't looping as I would expect. _________________ Life is too short to only write code in assembly... |
|
|
drh
Joined: 12 Jul 2004 Posts: 192 Location: Hemet, California USA
|
|
Posted: Sat Oct 16, 2010 8:36 am |
|
|
Here's a hint:
"number" is 16 bits. The SPI sends and receives 8 bits. _________________ David |
|
|
SkeeterHawk
Joined: 16 Oct 2010 Posts: 31 Location: Florissant, CO
|
Newbie question on program flow |
Posted: Sat Oct 16, 2010 10:34 am |
|
|
Thanks for your response. I was thinking that it had to do with that, but I just expected it to truncate the rest of the bits and that I would only get the most significant nybble out to the DAC. If that was the case, I would be able to tell pretty easily, but instead it is sending it all to the DAC correctly and I am not even truncating the LSNybble. The opposite is also true that it is not hanging in the SPI routine or anything due to buffer overflow or anything.
I have been programming in assembly for 12 years now and have a good grasp on what it happening at the bit level...I could bit-bang this in minutes, but that isn't the point as I am finally trying to master C. I guess if I need to do a logical shift or something and send the bits out...that is fine, but I know that I can't just send a "number + 1" in the address as I would in assembly. At this point I am clueless and it is embarrassing to say so . I guess it is that I am just not quite sure the best way to take a INT16 and break it down into two INT8's so I can send it across the bus...if this is indeed the problem for my not falling into the function that follows the write.
Like I said, this is a simple problem and it has had me for three days now. A hint on how I should structure this would be appreciated. I just want to see a stinkin' triangle wave come out of my DAC _________________ Life is too short to only write code in assembly... |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Oct 16, 2010 11:49 am |
|
|
Quote: |
I am just not quite sure the best way to take a INT16 and break it down
into two INT8's.
|
You need a CCS function reference. Download the manual and look in this section:
Quote: | BUILT-IN-FUNCTIONS
| http://www.ccsinfo.com/downloads/ccs_c_manual.pdf
It has a list of the CCS functions, and they are grouped by type of
operation that they perform.
For example, you want to know how to break up a 16-bit word into
two bytes. Scan down the list of summary names on the left side of
the page. This section will have what you need.
Quote: | BIT/BYTE
MANIPULATION
|
Then find the function name that fits your needs the best and click on it.
When you're new, you should keep the CCS manual on your Windows
desktop for easy access. |
|
|
Humberto
Joined: 08 Sep 2003 Posts: 1215 Location: Buenos Aires, La Reina del Plata
|
|
Posted: Sat Oct 16, 2010 12:12 pm |
|
|
Also it would be more easy to help you if we know what type DAC are you using in order know how to drive it,
and please post the full header of your code. |
|
|
SkeeterHawk
Joined: 16 Oct 2010 Posts: 31 Location: Florissant, CO
|
Newbie question on program flow |
Posted: Sat Oct 16, 2010 1:04 pm |
|
|
Thank you both very much for your input. Yes, I have been keeping the HELP for CCS minimized for the last few weeks. Now that you mention that, I see it there plain as day. I keep thinking that I will have to use the shift operators for such operations and don't think that there will be a built in function. This is what I am liking so much about the CCS compiler in particular is that it has all of the built in functions to make my job easier, but I have to learn the resources better. My thinking has to go from 8-bit to floating point, so it is taking me some time to understand how to accomplish the more mundane tasks. Thank you again for your help, PCM!
Sorry for not providing all of the details, Humberto. I was trying not to make you guys have to look at a bunch of (what I thought was) impertinent code. I still don't understand what is going on fundamentally here. I am not clear of why all 12 bits are getting sent to the DAC from only the one routine and why it refuses to go into the next. It seems that this SPI talk is just the protocol and has nothing to do with the program flow...unless it hangs in the communication routines or something, but that isn't the case here. It is just ignoring the rest of the code for some reason. I am going to modify my code to do the SPI write in two instances, and then try it all over again. Hopefully it will work, but I would like to understand what is going on beneath the surface to make it not work in this particular way.
I am using a TI DAC7611. I put comments, so you should know the logic. Here is my header file and the rest of the code...
Code: | #include <16F877A.h>
#device ICD=TRUE
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES NOPUT //No Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES DEBUG //Debug mode for use with ICD
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection
#FUSES NOWRT //Program memory not write protected
#use delay(clock=19660800)
#use rs232(baud=9600, UART1, xmit=PIN_C6, rcv=PIN_C7, parity=N, bits=8, stop=1) |
This is an include file that I have in the code, which is a generic one that I have been using during development.
I will see if I can satisfy the SPI and see if the world falls back into place.
Thanks again for all of your help. _________________ Life is too short to only write code in assembly... |
|
|
SkeeterHawk
Joined: 16 Oct 2010 Posts: 31 Location: Florissant, CO
|
Newbie question on program flow |
Posted: Sat Oct 16, 2010 1:46 pm |
|
|
OK, now I am really confused. I modified the code to do the SPI write in two steps and now it DOES indeed give me a triangle wave, but the output is only 10% of what it should be. This is weird...
Any insight you can give me into what is going on here would be MUCH appreciated! Here is my new code:
Code: | void main()
{
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_CLOCK_DIV_2);
setup_psp(PSP_DISABLED);
setup_spi(SPI_MASTER|SPI_L_TO_H|SPI_CLK_DIV_4);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
// setup_spi(spi_master); // Set up SPI master mode
output_low(PIN_C0); // Pull the DAC chip select low to enable the communication
while(1)
{
int16 number; // Declare the 16-bit integer number
int SPI_Num; // Declare the 8-bit value that will get sent over the SPI bus
for(number=0; number<1023; number++)
{
SPI_Num = Make8(number, 1); // Grab the MSNybble of the number result to send
spi_write(SPI_Num); // Output the MSNybble to the DAC
SPI_Num = Make8(number, 0); // Grab the LSByte of the number result to send
spi_write(SPI_Num); // Output the remaining byte to the DAC
output_low(PIN_C1); // Strobe the load DAC input
delay_ms(25); // Delay just a moment
output_high(PIN_C1); // Bring it high again
}
for(number=1023; number>0; number--)
{
SPI_Num = Make8(number, 1); // Grab the MSNybble of the number result to send
spi_write(SPI_Num); // Output the MSNybble to the DAC
SPI_Num = Make8(number, 0); // Grab the LSByte of the number result to send
spi_write(SPI_Num); // Output the remaining byte to the DAC
output_low(PIN_C1); // Strobe the load DAC input
delay_ms(25); // Delay just a moment
output_high(PIN_C1); // Bring it high again
}
}
} |
According to the timing, I am shifted over by 5-bits. What is going on here? _________________ Life is too short to only write code in assembly... |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Oct 16, 2010 2:02 pm |
|
|
The DAC data sheet says to shift in the data MSB first. It's likely that
they want it to be left justified. So, left-justify your 16-bit value before
you break it up into two bytes. But make a copy. Don't ruin your loop
index.
Also, this is a 12-bit DAC, and your loop counter only goes through 10 bits.
Just be aware of that. |
|
|
SkeeterHawk
Joined: 16 Oct 2010 Posts: 31 Location: Florissant, CO
|
|
Posted: Sat Oct 16, 2010 2:45 pm |
|
|
Quote: | this is a 12-bit DAC, and your loop counter only goes through 10 bits |
You are absolutely right! So that explains the offset. Thank you.
Thank you so much for all of your help.
OK, so for discussion now, can you help me understand why it chose not to execute the second part of my routine just because I was trying to shove a 16-bit integer through an 8-bit pipe? I don't understand how these are associated and I just want to be able to debug my own code in the future without having to bother you fine people... _________________ Life is too short to only write code in assembly... |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Oct 16, 2010 3:57 pm |
|
|
There are so many things wrong, I don't want to speculate on old code.
I noticed another problem. The SPI setup is using the incorrect mode:
Quote: | setup_spi(SPI_MASTER|SPI_L_TO_H|SPI_CLK_DIV_4); |
These are the #define statements for the four SPI modes:
Code: |
// SPI mode definitions.
#define SPI_MODE_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_1 (SPI_L_TO_H)
#define SPI_MODE_2 (SPI_H_TO_L)
#define SPI_MODE_3 (SPI_H_TO_L | SPI_XMIT_L_TO_H)
|
This shows that you are using SPI mode 1. The SPI mode is defined by
the idle state of SCLK, and the edge of SCLK that is used by the slave
to sample the data. The DAC sheets shows (on page 5), that SCLK idles
high and samples on the rising edge. See the mode diagram on this page:
http://www.totalphase.com/support/kb/10045/#modes
It shows that the SPI mode for the DAC is Mode 3. So your setup line
should be:
Code: | setup_spi(SPI_MASTER | SPI_MODE_3 | SPI_CLK_DIV_4 ); |
Because you were previously using Mode 1, the DAC was sampling the
data on the wrong edge, and this could possibly cause it to be shifted
"off by 1" bit. |
|
|
Humberto
Joined: 08 Sep 2003 Posts: 1215 Location: Buenos Aires, La Reina del Plata
|
|
Posted: Sat Oct 16, 2010 8:15 pm |
|
|
You are coming from Assembler, I assume that you already know "what" to do, hence the challenge for you is
"how to do it in C". I suggest debug these kind of problems with the help of an oscilloscope or at least debugging
with MPLAB with integrated CCS compiler.
Regarding your problem, the way is do it yourself to deeply understand the compiler behavior.
Another option -and the easyest one- is to use the built-in CCS function spi_xfer() to transfers data to and reads data from an SPI device.
Regards |
|
|
SkeeterHawk
Joined: 16 Oct 2010 Posts: 31 Location: Florissant, CO
|
Newbie question on program flow |
Posted: Sat Oct 16, 2010 9:44 pm |
|
|
Thank you both so much again for your response. It is greatly appreciated!
First, PCM is absolutely correct. Once I got the number of bits right from 10 to 12, my result was off by one bit. I didn't bring it up when I posted as I figured I would just debug it in hardware and that it had something to do with the edges...but you nailed it anyway!!! You have a great eye and we up-and-coming programmers are VERY fortunate to have your expert advice! That said, I just used the default from the project wizard for the SPI setup and didn't investigate the timing yet...and I will certainly be using Humberto's advice and run all of my demos with a scope attached. When I go back to the documentation, I don't see the defines for the SPI modes listed as you mentioned in the devices *.h file.
Regardless of the details of where the #define statements for the SPI modes are, you have helped "get me over the hump" and my code is working now. I will just start running with a scope by default and will make it my mission to understand my compiler better fundamentally in hopes that I may be able to contribute to this forum some day as well.
Thanks again, and my most sincere best wishes to you all. _________________ Life is too short to only write code in assembly... |
|
|
|
|
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
|