|
|
View previous topic :: View next topic |
Author |
Message |
cleberalbert
Joined: 25 Feb 2014 Posts: 34 Location: Brazil
|
Why are shown the 8 least significant bits if it's an int16? |
Posted: Sun Jul 27, 2014 6:13 pm |
|
|
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
|
|
Posted: Sun Jul 27, 2014 8:20 pm |
|
|
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
|
|
Posted: Sun Jul 27, 2014 11:06 pm |
|
|
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;
}
|
|
|
|
|
|
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
|