CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Newbie question on program flow

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
SkeeterHawk



Joined: 16 Oct 2010
Posts: 31
Location: Florissant, CO

View user's profile Send private message

Newbie question on program flow
PostPosted: Sat Oct 16, 2010 2:29 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Oct 16, 2010 8:36 am     Reply with quote

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

View user's profile Send private message

Newbie question on program flow
PostPosted: Sat Oct 16, 2010 10:34 am     Reply with quote

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 Embarassed. 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 Confused
_________________
Life is too short to only write code in assembly...
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sat Oct 16, 2010 11:49 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Oct 16, 2010 12:12 pm     Reply with quote

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

View user's profile Send private message

Newbie question on program flow
PostPosted: Sat Oct 16, 2010 1:04 pm     Reply with quote

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

View user's profile Send private message

Newbie question on program flow
PostPosted: Sat Oct 16, 2010 1:46 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Oct 16, 2010 2:02 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Oct 16, 2010 2:45 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Oct 16, 2010 3:57 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Oct 16, 2010 8:15 pm     Reply with quote

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

View user's profile Send private message

Newbie question on program flow
PostPosted: Sat Oct 16, 2010 9:44 pm     Reply with quote

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...
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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