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

help required with programming PIC code

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



Joined: 21 Oct 2005
Posts: 3

View user's profile Send private message Send e-mail

help required with programming PIC code
PostPosted: Fri Oct 21, 2005 6:36 am     Reply with quote

hi there

I am trying to program a PIC16F873 device using another PIC16F873A device. i have been trying to follow the timing diagrams that are shown in the programming specification guides.

I am new to this compiler and have to tried to convert from the cc5x compiler. I have posted my code below. there is a function to put the device into program/verify mode, another to send a command, another to read data and another one to send data.
Can someone tell me if it looks correct.
All help will be greatly appreciated.
thanks

Code:

#include <16F873.h>
#use delay(clock=4000000)
#fuses XT,NOWDT
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=9)

#define PIC_CMD_LOADCONFIG 0x00
#define PIC_CMD_READPROGRAM 0x02
#define PIC_CMD_INCADDRESS 0x06

#define P_MCLR PIN_B0 //Pin MCLR
#define P_DATA PIN_B1 //pin RB7
#define P_CLOCK PIN_B2 //pin RB6
#ifndef WORD
#define WORD unsigned short
#endif

char Ch;

RDA_isr() {
putc('a');
Ch = getc();

}

void program_mode()  //suppose to put device into program/verify mode
{
   output_low(P_DATA);
   output_low(P_CLOCK);
   output_low(P_MCLR);
   delay_us(0.1);
   output_high(P_MCLR);

}
void send_command(unsigned char cmd) //sends out a command and the //clock cycles six times
{
   char i;
   unsigned char b;
   output_high(P_MCLR);
   delay_cycles(5);

   for(i = 0; i< 6; i++)
   {
      output_high(P_CLOCK);
      if( bit_test(cmd, i))
      {
         output_high(P_DATA);
      }
      else
      {
         output_low(P_DATA);
      }
      output_low(P_CLOCK);
//cmd >> = 1;

   }

}



void sendData(unsigned int tempData)//sends out data word
{

   char i;
   unsigned char b;

   for (i=0; i<16; i++)
   {
      output_high(P_CLOCK);
      if( bit_test(tempData, i))
      {
         output_high(P_DATA);
      }
      else
      {
         output_low(P_DATA);
      }
      output_low(P_CLOCK);
   }



}

unsigned int readData() //reads in a data word
{
   char i;
   unsigned int tempData = 0;

   for (i = 0; i<16; i++)
   {
      output_high(P_CLOCK);
      if(input(P_DATA))
      {
         tempData |= 0x8000;
      }
      else {
      tempData |= 0x0000;
      }

      output_high(P_CLOCK);
      tempData >>= 1;
    }

    tempData >>= 1;
    tempData &= 0x3FFF;
    return tempData;
}

WORD read_DeviceID() //suppose to read the device ID
{  int i;
   unsigned int idData;
   send_command(PIC_CMD_LOADCONFIG);
   sendData(0);
   for(i = 0; i<6; i++)
   {
      send_command(PIC_CMD_INCADDRESS);
   }
   send_command(PIC_CMD_READPROGRAM);
   idData = readData();
   return idData;
     
}


void main() {

   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_CLOCK_DIV_2);
   setup_spi(FALSE);
   setup_counters(RTCC_INTERNAL,RTCC_DIV_2);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   enable_interrupts(INT_RDA);
   enable_interrupts(global);
   //send_command(PIC_INCADDRESS);
   read_deviceID();

}

PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Oct 21, 2005 1:10 pm     Reply with quote

I'll go through your code and make comments.

Quote:
#fuses XT,NOWDT

What programmer are you using to program your PIC ?
Is it a Low Voltage Programmer such as TLVP ? If not, and if you're
using a standard programmer, such as ICD2, PicStart-Plus, Warp13a,
CCS ICD, and many more, then you should add NOLVP to the fuses.
Also, it wouldn't hurt to add BROWNOUT and PUT. Example:
Code:
#fuses XT, NOWDT, BROWNOUT, PUT, NOLVP


Quote:

#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=9)

Are you really using 9 bits ? That's not very common.
Also, you should add the ERRORS parameter, which will cause
the compiler to clear any receive overrun errors automatically.
Example:
Code:
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7, ERRORS)


Quote:
#ifndef WORD
#define WORD unsigned short
#endif

This is wrong. You need to study CCS data types. They are listed
on page 86 (in Acrobat reader) of the October 2005 manual.
http://www.ccsinfo.com/ccscmanual.zip
In CCS a "short" is a 1-bit integer. So if you really want "WORD"
to be a 16-bit unsigned integer, then do this:
Code:
typedef int16 WORD;

Also, all integer data types in CCS are unsigned by default.

Quote:
RDA_isr() {
putc('a');
Ch = getc();
}

You're missing the CCS directive #int_rda, which tells the compiler
that RDA_isr() is an isr. Example:
Code:
#int_rda
RDA_isr()
{
Ch = getc();
putc('a');
}


Quote:
delay_us(0.1);

This is wrong. No floating point arguments may be used with delay_us().
Read the manual. Download it at the link given above.
Also, you're trying to delay for 100 ns ? Your crystal is only 4 MHz.
One instruction cycle is 1 us. You can't do a 100 ns delay.

Quote:

unsigned int tempData = 0;
tempData |= 0x8000;

You need to study the CCS data types. In CCS an "int" is an
8-bit unsigned integer. You want a 16-bit unsigned integer.
You need to declare it like this:
Code:
int16 tempData = 0;


Quote:
void main() {
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_CLOCK_DIV_2);
setup_spi(FALSE);
setup_counters(RTCC_INTERNAL,RTCC_DIV_2);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
enable_interrupts(INT_RDA);
enable_interrupts(global);
//send_command(PIC_INCADDRESS);
read_deviceID();
}


You're doing a whole bunch of unnecessary things here. I assume
you're using PCW, which tends to put in all these stuff ? But even
then, you're not using the A/D converter, so why setup the ADC clock ?
And, your crystal frequency is 4 MHz, and the data sheet says to use
"Divide by 8" for that. Example: ADC_CLOCK_DIV_8

For "read_deviceID();" that function returns a value. You're not
putting the return value into a variable. Just letting you know.

Finally, you're letting the program fall off the edge of main(). If you
do that, the PIC will execute a hidden SLEEP instruction that CCS puts
at the end of main. To avoid this, put a while(1); statement right before
the closing brace of main(). That's important.
ADD



Joined: 21 Oct 2005
Posts: 3

View user's profile Send private message Send e-mail

PostPosted: Fri Oct 21, 2005 3:12 pm     Reply with quote

hi there

thanks for posting your reply. Actually i have to make my own programmer and in this programmer, there is one PIC that is programming another PIC. At the moment for testing purposes, i am using the ICD2.

ok i have added the NOLVP and the BROWNOUT and the PUT.

thanks for spotting out the 9 bits. i didnt realise it when i put the RS232 stuff in. i have changed it to 8 bits.

i tried using typedef int16 WORD; but it gave me an error saying expecting a basic type.

IS there anyway that i can add a delay of 100ns? the datasheets say that there should be a minimum delay of 100ns after the MCLR pin has been put to high so if i cant use 100ns would it still be ok if i used 1us?

yes i am using the PCW compiler.

the way that i have put the return value into a variable is as follows.



Code:

void main()
{
int storage;
storage = read_DeviceID();
while(1);
}


Is that the correct way?

Does the rest of my code make sense? now there is one other thing that i want to ask you.

I have to write other functions in a similar manner such as erase, program, read and verify. these functions should be acted upon the target device. if i am not mistaken, they should all work in the same manner. So what i want to know is that for instance like i have written the read_deviceID function above. How exactly do i test the function to see if it is working? And another thing is that what exactly am i expected to see?

All help will be greatly appreciated.
thanks
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Oct 21, 2005 3:31 pm     Reply with quote

Quote:
i tried using typedef int16 WORD; but it gave me an error saying expecting a basic type.

It works OK with the following test program, which was compiled
with PCM vs. 3.235:
Code:

#include <16F877.H>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=4000000)

typedef int16 WORD;

//======================================
main(void)
{
WORD value;

value = 0x1234;

while(1);
}


Quote:
Is there anyway that i can add a delay of 100ns?

No.
Quote:
the datasheets say that there should be a minimum delay of 100ns after the MCLR pin has been put to high so if i cant use 100ns would it still be ok if i used 1us?

Yes.


Quote:

The way that i have put the return value into a variable is as follows.

void main()
{
int storage;
storage = read_DeviceID();
while(1);
}

Is that the correct way?

If read_Device() is supposed to return a 16-bit value, then it's wrong.
Remember that in CCS, an "int" is an unsigned 8-bit value. So you're
putting a 16-bit value into an 8-bit variable. I suggest that to avoid
confusion, you should use the special CCS names for unsigned integer
data types:

int1
int8
int16
int32

Quote:
How exactly do i test the function to see if it is working?

You could make a small test program that calls a function continuously
in a while(1) loop. The function will be called at a sufficient rate, so
that you can sync on the signals with your oscilloscope. Of course, if
you have a logic analyzer, that's better. Then you can look at the
signals, which are basically just SPI-style signals, and compare them
to the timing diagrams given in the Microchip programming document.
This will tell you if you have the proper number of clocks, and if you
have the correct relationship between the clock edge and data, etc.
ADD



Joined: 21 Oct 2005
Posts: 3

View user's profile Send private message Send e-mail

PostPosted: Fri Oct 21, 2005 3:54 pm     Reply with quote

ok thanks it works now. it was like really strange. i had it first right on top of my declaration list and it gave me an error but when it is after another declaration, it works for instance

Code:

char Ch;
typedef int16 WORD;


so basically what you are saying is that an int is a unsigned value am I right? and for instance if it is

int1 then it is a 1 bit variable
int 8 - 8bit variable etc.



Quote:

You could make a small test program that calls a function continuously
in a while(1) loop. The function will be called at a sufficient rate, so
that you can sync on the signals with your oscilloscope. Of course, if
you have a logic analyzer, that's better. Then you can look at the
signals, which are basically just SPI-style signals, and compare them
to the timing diagrams given in the Microchip programming document.
This will tell you if you have the proper number of clocks, and if you
have the correct relationship between the clock edge and data, etc.



ok cool. so this is what i have been doing so far. i program the device using my ICD2 and then connect the oscilloscope to the data and the clock pins and then while the PIC is being programmed, i check the signals. Ok i am getting the correct signals out from the oscilloscope as far as i can see.

now for instance i want to write a program that can read from the target device. I have been trying to follow the programming specification guide and also have looked at the source code for freeware such as WINPIC and have tried to use that same idea. Now how would i test if my code is actually reading from the device and what exactly would i see to confirm that the device is being read. Another thing is that when testing the code, do i have to connect the target PIC to the master PIC with its output pins? What would be the proper procedure?

thanks
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Oct 21, 2005 4:45 pm     Reply with quote

Quote:
so basically what you are saying is that an int is a unsigned value am I right? and for instance if it is

int1 then it is a 1 bit variable
int 8 - 8bit variable etc.

That's right.

Quote:
Now how would i test if my code is actually reading from the device and what exactly would i see to confirm that the device is being read.

Make a test program that does one operation, and a simple one,
such as reading the Device ID. Use the "Read Data from Program
Memory" command to do this. Then display the result in a terminal
window on your PC with a printf statement.

Look at page 12 in the Programming Specification for the 16F873:
http://ww1.microchip.com/downloads/en/DeviceDoc/39025f.pdf
It has a table with the Device ID values for the 16F87x PICs.
The address of the Device ID word is given on page 4.

If everything is working correctly, when you read address 0x2006,
for the 16F873, then you should see (in binary format):

00 1001 011 x xxxx

The x's are the silicon revision. Microchip doesn't give the raw
silicon revision values for the 16F87x series in any place that I can find.

Let's just assume that Revision B5 has a code of 0 0101.
Then the word would be:

00 1001 011 0 0101

Group that into nibbles, and add two leading zeros, to get this:

0000 1001 0110 0101

Translate that to hex:

0x0965

You should see some number like that as the Device ID/ Silicon Revision
word at address 0x2006.
ADD



Joined: 21 Oct 2005
Posts: 3

View user's profile Send private message Send e-mail

PostPosted: Sat Oct 22, 2005 4:31 am     Reply with quote

hi there

thanks for your reply. Ok this is what i have written in my code. Does it seem sort of right to test if i can read the deviceID? i am not exactly sure how these built-in functions were so just want to confirm.

Code:

WORD read_DeviceID()
{  int i;
   unsigned int idData;
   send_command(PIC_CMD_LOADCONFIG);
   sendData(0x3FFF);
   for(i = 0; i<6; i++)
   {
      send_command(PIC_CMD_INCADDRESS);
   }
idData = read_program_eeprom(i);
printf(" the device ID is %2X\r\n", idData);

   //send_command(PIC_CMD_READPROGRAM);
   //idData = readData();
   
   return idData;

}

void main() {

   int16 storage;
   storage = read_deviceID();
   while(1);
}


would that work? the other functions such as send_command are shown in the previous post. i am still trying to test to see if code would work. the only thing is that i cant seem to get my ICD2 work with the RS232 cable. it works with the USB. thats why i need to sort of have an idea if the code looks right.

just a thought though while posting this post. would it work if i use the ICD2 via the USB port to program the device on the demo board and then connect the demo board using a RS232 cable to the PC and then use hyperterminal to see if something is coming out?

Another thing is that i just need that one programmed PIC to test right now right? i dont need the target PIC to be connected to the programmed PIC right.

thanks
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sat Oct 22, 2005 10:04 am     Reply with quote

Quote:
would that work? the other functions such as send_command are
shown in the previous post. i am still trying to test to see if code would
work. the only thing is that i cant seem to get my ICD2 work with the
RS232 cable. it works with the USB. thats why i need to sort of have an
idea if the code looks right.

You don't need it working with the RS232 cable. Use USB.

Quote:
just a thought though while posting this post. would it work if i use
the ICD2 via the USB port to program the device on the demo board and
then connect the demo board using a RS232 cable to the PC and then use
hyperterminal to see if something is coming out?

That's what I meant.

Quote:

Another thing is that i just need that one programmed PIC to test right
now right? i dont need the target PIC to be connected to the programmed
PIC right.

It depends on what sort of testing you want to do.

Quote:

this is what i have written in my code. Does it seem sort of right to test
if i can read the deviceID? i am not exactly sure how these built-in
functions were so just want to confirm.

It doesn't look right to me. It doesn't fit the 16F87x Programming
Specification for the Read Data command. They don't show sending
the command 6 times, as you are doing. The Send_Command()
routine sends 6 bits. You need to look at your own code.
Also, you're using the read_program_eeprom() function which reads
program memory on the PIC on the Demo board. Your goal is
read data from the Target PIC, not the one on the Demo board.
You do this by toggling the clock and data lines going to the Target PIC,
not by reading program memory on the Demo board PIC.

Quote:
I also have looked at the source code for freeware such as WINPIC

You must do the project. You have sample code. Follow it.
I don't want to approve every routine as you write them.

My goal in answering your post was to give you some tips on
translating code from CC5x to CCS. I basically have done that.
I don't want to write your routines or do your project for you.
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