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

Why are shown the 8 least significant bits if it's an int16?

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



Joined: 25 Feb 2014
Posts: 34
Location: Brazil

View user's profile Send private message

Why are shown the 8 least significant bits if it's an int16?
PostPosted: Sun Jul 27, 2014 6:13 pm     Reply with quote

Hi all!
Could someone help me with this little problem? I'm trying to show an int16 data but are shown only the 8 least significant bits.

Explaining all:
I've 2 PICs which they interact each other using I2C protocol. The master sends an int16 data to the slave which sends back the same int16 data to the master.
The master shows the data (On PC by serial protocol) twice: before sending and after receiving and it shows the same int16 data as should be. So, everything is ok until here! But in the meantime the slave sends back correctly the same int16 data to the master, the slave shows only the 8 least significant bits (On PC by serial protocol). So I don't know why slave doesn't show all the 16 bits as should be. Could someone help me with this little problem?

to illustrate my explanation step by step:
1 - The master sends the data 18099 (100011010110011) to the Slave by I2C protocol
2 - The master shows on the PC what was sent (18099) by Serial protocol
3 - The slave receive the data and sends back the same data (18099) by I2C protocol
4 - The slave shows on the PC what was sent back but is shown only the 8 least significant bits (179 -> 10110011) by Serial protocol
5 - The master shows on the PC what was received (18099) by Serial protocol

I'm using the CCS Compiler version 5.018

The code of the slave PIC is below: (only one printf)

Code:

printf("First Successful read and write back to the Master: %ld\n", tx_byte);

The tx_byte variable is declared as int16.

All the code:
Code:

#include <18f4520.h>

#fuses HS
#fuses PUT
#fuses NOWDT                    //No Watch Dog Timer
#fuses NOBROWNOUT               //No brownout reset
#fuses NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#fuses NOXINST                  //Extended set extension and Indexed Addressing mode disabled (Legacy mode)

#use delay(crystal=20MHz)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) //+++ up baud rate?
#use i2c(master, sda=PIN_C4, scl=PIN_C3, FORCE_HW)

/* Bit defines */
#define PIC_SSPSTAT_BIT_SMP     0x80
#define PIC_SSPSTAT_BIT_CKE     0x40
#define PIC_SSPSTAT_BIT_DA      0x20
#define PIC_SSPSTAT_BIT_P       0x10
#define PIC_SSPSTAT_BIT_S       0x08
#define PIC_SSPSTAT_BIT_RW      0x04
#define PIC_SSPSTAT_BIT_UA      0x02
#define PIC_SSPSTAT_BIT_BF      0x01

#define PIC_SSPCON1_BIT_WCOL    0x80
#define PIC_SSPCON1_BIT_SSPOV   0x40
#define PIC_SSPCON1_BIT_SSPEN   0x20
#define PIC_SSPCON1_BIT_CKP     0x10
#define PIC_SSPCON1_BIT_SSPM3   0x08
#define PIC_SSPCON1_BIT_SSPM2   0x04
#define PIC_SSPCON1_BIT_SSPM1   0x02
#define PIC_SSPCON1_BIT_SSPM0   0x01

#define PIC_SSPCON2_BIT_GCEN    0x80
#define PIC_SSPCON2_BIT_ACKSTAT 0x40
#define PIC_SSPCON2_BIT_ACKDT   0x20
#define PIC_SSPCON2_BIT_ACKEN   0x10
#define PIC_SSPCON2_BIT_RCEN    0x08
#define PIC_SSPCON2_BIT_PEN     0x04
#define PIC_SSPCON2_BIT_RSEN    0x02
#define PIC_SSPCON2_BIT_SEN     0x01

/* Parameters */
#define RX_BUF_LEN  4 //8 //32
#define LOGBUF_MASK 0x07
#define NODE_ADDR   0x20 /* I2C address of the slave node (avoid addr masking) */

/* PIC Registers */
#byte PIC_SSPBUF   = 0xfc9
#byte PIC_SSPADD   = 0xfc8
#byte PIC_SSPSTAT  = 0xfc7
#byte PIC_SSPCON1  = 0xfc6
#byte PIC_PIE1     = 0xf9d
#byte PIC_TRISC    = 0xf94

#byte PIC_SSPCON2  = 0xfc5

int8 buffer_index;
int8 comms_error;
int8 debug_state;
int8 error_sspstat;
int16 slave_buffer[RX_BUF_LEN];

// Prototypes
int16 read_i2c(void);
void i2c_interrupt_handler(void);
void i2c_initialize(void);
void i2c_error(int8 temp_sspstat);
void write_i2c(int16 transmit_byte);
void toggle_light(void);
void wait_for_bf_low(void);

#INT_SSP
void ssp_interupt ()
{
  i2c_interrupt_handler();
}

void i2c_initialize(void)
{
  debug_state = 0;

  /* Set up SSP module for 7-bit */
  while (PIC_SSPCON2 & 0x1f) {
    // ACKEN RCEN PEN RSEN SEN all must be zero
  }
  PIC_SSPSTAT = 0x00;     /* Clear the SSPSTAT register. */
  PIC_SSPCON1 = 0x36;   /* 0011 0101 */
  PIC_SSPADD = NODE_ADDR;  /* Set the slave's address */
  /* init buffers */
  buffer_index = 0;
  /* Go */
  enable_interrupts(INT_SSP);  /* Enable MSSP interrupts. */
}   

void i2c_interrupt_handler(void)
{
    int16 i2c_mask = 0x2D;  /* 0010 1101 */
    int16 temp_sspstat;
    int16 this_byte;
    int16 tx_byte;
    int8 x;

    /* Mask out the unnecessary bits */
    temp_sspstat = PIC_SSPSTAT & i2c_mask;
   
    switch (temp_sspstat) {
      /* Write operation, last byte was an address, buffer is full */
    case 0x09:   /* 0000 1001 */
      /* Clear the receive buffer */
      for (x=0; x<RX_BUF_LEN; x++)
   {
     slave_buffer[x] = 0x00;
   }
      buffer_index = 0;  /* Clear the buffer index */
      this_byte = read_i2c();   /* Do a dummy read of PIC_SSPBUF */
           
      debug_state = 1;
      break;
       
      /* Write operation, last byte was data, buffer is full */
    case 0x29:   /* 0010 1001 */
      /* Point to the buffer */
      this_byte = read_i2c();  /* Get the byte from the SSP */
      slave_buffer[buffer_index] = this_byte; /* Put it into the buffer */
      buffer_index++; /* Increment the buffer pointer */
#ifdef I2C_DAEMON
      // If enough data is in, this would move it to application's double buffer
      i2c_double_buffer_daemon();
#endif // I2C_DAEMON
      /* Get the current buffer index */
      /* Subtract the buffer length */
      /* Has the index exceeded the buffer length? */
      if (buffer_index >= RX_BUF_LEN)
   {
     buffer_index = 0; /* Yes, clear the buffer index. */
   }
      debug_state = 2;
      break;
       
      /* Read operation; last byte was an address, buffer is empty */
    case 0x0C:   /* 0000 1100 */
    label_0c:
      buffer_index = 0; /* Clear the buffer index */
      /* Point to the buffer */
      tx_byte = slave_buffer[buffer_index]; /* Get byte from the buffer */
      printf("First Successful read and write back to the Master: %ld\n", tx_byte);
      write_i2c(tx_byte); /* Write the byte to PIC_SSPBUF */
      buffer_index++; /* increment the buffer index */
      debug_state = 3;
      break;
       
      /* Read operation; last byte was data, buffer is empty */
    case 0x2C:   /* 0010 1100 */
      /* Get the current buffer index */
      /* Subtract the buffer length */
      /* Has the index exceeded the buffer length? */
      if (buffer_index >= RX_BUF_LEN)
   {
     buffer_index = 0; /* Yes, clear the buffer index */
   }
      /* Point to the buffer */
      /* Get the byte */
      tx_byte = slave_buffer[buffer_index]; 
      write_i2c(tx_byte);  /* Write to PIC_SSPBUF */
      buffer_index++; /* increment the buffer index */
      debug_state = 4;
      break;
           
      /* A NACK was received when transmitting data back [to] the master. */
      /* Slave logic is reset in this case. R_W=0, D_A=1, and BF=0. */
      /* If we don't stop in this state, then something is wrong!! */
    case 0x28:   /* 0010 1000 */
      debug_state = 5;
      break;
       
      /* Read operation; last byte was address, buffer is full */
    case 0x0d:
      this_byte = read_i2c();   // Do a dummy read of PIC_SSPBUF to clear it
      wait_for_bf_low();
      goto label_0c; // reduced to the normal case
      /* Something went wrong!! */
    default:
      debug_state = 0xe;
      break;
    }
}

void i2c_error(int8 temp_sspstat)
{
    comms_error = 1;
    error_sspstat = temp_sspstat;
}

void write_i2c(int16 transmit_byte)
{
    int16 write_collision = 1;
 
    while (PIC_SSPSTAT & PIC_SSPSTAT_BIT_BF) /* Is BF bit set in PIC_SSPSTAT? */
    {
        /* If yes, then keep waiting */
    }
   
    while (write_collision)
    {
        /* If not, then do the i2c_write. */   
        PIC_SSPCON1 &= ~PIC_SSPCON1_BIT_WCOL;  /* Clear the WCOL flag */
        PIC_SSPBUF = transmit_byte;
   
        /* Was there a write collision? */
        if (PIC_SSPCON1 & PIC_SSPCON1_BIT_WCOL)
        {
            /* Yes there was a write collision. */
            write_collision = 1;
        }
        else
        {
            /* NO, there was no write collision. */
            /* The transmission was successful */
            write_collision = 0;
        }
    }
    PIC_SSPCON1 |= PIC_SSPCON1_BIT_CKP;  /* Release the clock. */
}

/* This function returns the byte in SSPBUF */
int16 read_i2c(void)
{
    return PIC_SSPBUF;
}

void wait_for_bf_low(void)
{
  while(PIC_SSPSTAT & 0x1);
}

void main (void)
{
  debug_state = 0;
  i2c_initialize();
  enable_interrupts(GLOBAL);
 
  while (TRUE)
  if (debug_state)
  debug_state = 0;
  }
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Jul 27, 2014 8:20 pm     Reply with quote

The only place that you load the 'slave_buffer' array is here:
Code:

int16 slave_buffer[RX_BUF_LEN];
int16 this_byte;

this_byte = read_i2c();  /* Get the byte from the SSP */
slave_buffer[buffer_index] = this_byte;


The read_i2c() function only gets one byte. That's how it works.
The SSPBUF is only 8-bits wide. The read_i2c() function will therefore
return a value in this format: 0x00nn
Code:

/* This function returns the byte in SSPBUF */
int16 read_i2c(void)
{
    return PIC_SSPBUF;
}
 

So when you load 'this_byte', it will be 0x00nn. The upper byte will be 0.

Then, you load the slave_buffer[] array with 'this_byte'. So, the int16
array element will also be in this format: 0x00nn.

Then you print the value from slave_buffer[]:
Code:

tx_byte = slave_buffer[buffer_index]; /* Get byte from the buffer */
      printf("First Successful read and write back to the Master: %ld\n", tx_byte);

But 'tx_byte' is loaded with the same data, which is in this format: 0x00nn
Then you print it, and of course you get the upper byte = 0x00.

I'm not certain, but I think you may believe that if you give an int16
parameter to an 8-bit device (the SSP), then it will automatically send
or receive both bytes. It won't do it. It's 8-bit only. You have to
send the two bytes as separate 8-bit operations.
cleberalbert



Joined: 25 Feb 2014
Posts: 34
Location: Brazil

View user's profile Send private message

PostPosted: Sun Jul 27, 2014 11:06 pm     Reply with quote

Programador PCM, Thanks!!

You made me see that the most signification bits are in another case of the switch! I had no paid attention about that. Now I make an int16 by make16 function. As soon as I finish it I'll publish it in the code library.

but now i've another problem which i "corrected" using a counter and if. Why the i2c_interrupt_handler() function acts twice? I think it should act only once. I know that because the case 0x2C acts twice before i was using a counter and if. How can i make the i2c_interrupt_handler() function act only once?

current code:
Code:

#include <18f4520.h>

#fuses HS
#fuses PUT
#fuses NOWDT                    //No Watch Dog Timer
#fuses NOBROWNOUT               //No brownout reset
#fuses NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#fuses NOXINST                  //Extended set extension and Indexed Addressing mode disabled (Legacy mode)

#use delay(crystal=20MHz)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) //+++ up baud rate?
#use i2c(master, sda=PIN_C4, scl=PIN_C3, FORCE_HW)

/* Bit defines */
#define PIC_SSPSTAT_BIT_SMP     0x80
#define PIC_SSPSTAT_BIT_CKE     0x40
#define PIC_SSPSTAT_BIT_DA      0x20
#define PIC_SSPSTAT_BIT_P       0x10
#define PIC_SSPSTAT_BIT_S       0x08
#define PIC_SSPSTAT_BIT_RW      0x04
#define PIC_SSPSTAT_BIT_UA      0x02
#define PIC_SSPSTAT_BIT_BF      0x01

#define PIC_SSPCON1_BIT_WCOL    0x80
#define PIC_SSPCON1_BIT_SSPOV   0x40
#define PIC_SSPCON1_BIT_SSPEN   0x20
#define PIC_SSPCON1_BIT_CKP     0x10
#define PIC_SSPCON1_BIT_SSPM3   0x08
#define PIC_SSPCON1_BIT_SSPM2   0x04
#define PIC_SSPCON1_BIT_SSPM1   0x02
#define PIC_SSPCON1_BIT_SSPM0   0x01

#define PIC_SSPCON2_BIT_GCEN    0x80
#define PIC_SSPCON2_BIT_ACKSTAT 0x40
#define PIC_SSPCON2_BIT_ACKDT   0x20
#define PIC_SSPCON2_BIT_ACKEN   0x10
#define PIC_SSPCON2_BIT_RCEN    0x08
#define PIC_SSPCON2_BIT_PEN     0x04
#define PIC_SSPCON2_BIT_RSEN    0x02
#define PIC_SSPCON2_BIT_SEN     0x01

/* Parameters */
#define RX_BUF_LEN  4 //8 //32
#define LOGBUF_MASK 0x07
#define NODE_ADDR   0x20 /* I2C address of the slave node (avoid addr masking) */

/* PIC Registers */
#byte PIC_SSPBUF   = 0xfc9
#byte PIC_SSPADD   = 0xfc8
#byte PIC_SSPSTAT  = 0xfc7
#byte PIC_SSPCON1  = 0xfc6
#byte PIC_PIE1     = 0xf9d
#byte PIC_TRISC    = 0xf94

#byte PIC_SSPCON2  = 0xfc5

int8 buffer_index;
int8 comms_error;
int8 debug_state;
int8 error_sspstat;
int16 slave_buffer[RX_BUF_LEN];
int8 made=0;


// Prototypes
int16 read_i2c(void);
void i2c_interrupt_handler(void);
void i2c_initialize(void);
void i2c_error(int8 temp_sspstat);
void write_i2c(int16 transmit_byte);
void toggle_light(void);
void wait_for_bf_low(void);

#INT_SSP
void ssp_interupt ()
{
  i2c_interrupt_handler();
}

void i2c_initialize(void)
{
  debug_state = 0;

  /* Set up SSP module for 7-bit */
  while (PIC_SSPCON2 & 0x1f) {
    // ACKEN RCEN PEN RSEN SEN all must be zero
  }
  PIC_SSPSTAT = 0x00;     /* Clear the SSPSTAT register. */
  PIC_SSPCON1 = 0x36;   /* 0011 0101 */
  PIC_SSPADD = NODE_ADDR;  /* Set the slave's address */
  /* init buffers */
  buffer_index = 0;
  /* Go */
  enable_interrupts(INT_SSP);  /* Enable MSSP interrupts. */
}   

void i2c_interrupt_handler(void)
{
    int16 i2c_mask = 0x2D;  /* 0010 1101 */
    int16 temp_sspstat;
    int16 this_byte;
    int16 lsb_tx_byte;
    int16 hsb_tx_byte;
    int16 tx_byte;
    int8 x;
   
    /* Mask out the unnecessary bits */
    temp_sspstat = PIC_SSPSTAT & i2c_mask;
   
    switch (temp_sspstat) {
      /* Write operation, last byte was an address, buffer is full */
    case 0x09:   /* 0000 1001 */
      /* Clear the receive buffer */
      for (x=0; x<RX_BUF_LEN; x++)
   {
     slave_buffer[x] = 0x00;
   }
      buffer_index = 0;  /* Clear the buffer index */
      this_byte = read_i2c();   /* Do a dummy read of PIC_SSPBUF */
           
      debug_state = 1;
      break;
       
      /* Write operation, last byte was data, buffer is full */
    case 0x29:   /* 0010 1001 */
      /* Point to the buffer */
      this_byte = read_i2c();  /* Get the byte from the SSP */
      slave_buffer[buffer_index] = this_byte; /* Put it into the buffer */
      buffer_index++; /* Increment the buffer pointer */
#ifdef I2C_DAEMON
      // If enough data is in, this would move it to application's double buffer
      i2c_double_buffer_daemon();
#endif // I2C_DAEMON
      /* Get the current buffer index */
      /* Subtract the buffer length */
      /* Has the index exceeded the buffer length? */
      if (buffer_index >= RX_BUF_LEN)
   {
     buffer_index = 0; /* Yes, clear the buffer index. */
   }
      debug_state = 2;
      break;
       
      /* Read operation; last byte was an address, buffer is empty */
    case 0x0C:   /* 0000 1100 */
    label_0c:
      buffer_index = 0; /* Clear the buffer index */
      /* Point to the buffer */
      lsb_tx_byte = slave_buffer[buffer_index]; /* Get byte from the buffer */
      write_i2c(lsb_tx_byte); /* Write the byte to PIC_SSPBUF */
      buffer_index++; /* increment the buffer index */
      debug_state = 3;
      break;
       
      /* Read operation; last byte was data, buffer is empty */
    case 0x2C:   /* 0010 1100 */
      /* Get the current buffer index */
      /* Subtract the buffer length */
      /* Has the index exceeded the buffer length? */
      if (buffer_index >= RX_BUF_LEN)
   {
     buffer_index = 0; /* Yes, clear the buffer index */
   }
      /* Point to the buffer */
      /* Get the byte */
      hsb_tx_byte = slave_buffer[buffer_index]; 
      tx_byte=make16(hsb_tx_byte, lsb_tx_byte);
      if(made==0)
      printf("Secound Successful read and write back to the Master: %ld\n",tx_byte);
      made++;
      write_i2c(hsb_tx_byte);  /* Write to PIC_SSPBUF */
      buffer_index++; /* increment the buffer index */
      debug_state = 4;
      break;
           
      /* A NACK was received when transmitting data back [to] the master. */
      /* Slave logic is reset in this case. R_W=0, D_A=1, and BF=0. */
      /* If we don't stop in this state, then something is wrong!! */
    case 0x28:   /* 0010 1000 */
      debug_state = 5;
      break;
       
      /* Read operation; last byte was address, buffer is full */
    case 0x0d:
      this_byte = read_i2c();   // Do a dummy read of PIC_SSPBUF to clear it
      wait_for_bf_low();
      goto label_0c; // reduced to the normal case
      /* Something went wrong!! */
    default:
      debug_state = 0xe;
      break;
    }
}

void i2c_error(int8 temp_sspstat)
{
    comms_error = 1;
    error_sspstat = temp_sspstat;
}

void write_i2c(int16 transmit_byte)
{
    int16 write_collision = 1;
 
    while (PIC_SSPSTAT & PIC_SSPSTAT_BIT_BF) /* Is BF bit set in PIC_SSPSTAT? */
    {
        /* If yes, then keep waiting */
    }
   
    while (write_collision)
    {
        /* If not, then do the i2c_write. */   
        PIC_SSPCON1 &= ~PIC_SSPCON1_BIT_WCOL;  /* Clear the WCOL flag */
        PIC_SSPBUF = transmit_byte;
   
        /* Was there a write collision? */
        if (PIC_SSPCON1 & PIC_SSPCON1_BIT_WCOL)
        {
            /* Yes there was a write collision. */
            write_collision = 1;
        }
        else
        {
            /* NO, there was no write collision. */
            /* The transmission was successful */
            write_collision = 0;
        }
    }
    PIC_SSPCON1 |= PIC_SSPCON1_BIT_CKP;  /* Release the clock. */
}

/* This function returns the byte in SSPBUF */
int16 read_i2c(void)
{
    return PIC_SSPBUF;
}

void wait_for_bf_low(void)
{
  while(PIC_SSPSTAT & 0x1);
}

void main (void)
{
  debug_state = 0;
  i2c_initialize();
  enable_interrupts(GLOBAL);
 
  while (TRUE)
  if (debug_state)
  debug_state = 0;
  }
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