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

Reading MCP4725, rotating and concatenating two bytes

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



Joined: 19 Sep 2018
Posts: 15

View user's profile Send private message

Reading MCP4725, rotating and concatenating two bytes
PostPosted: Sat Nov 16, 2019 3:40 am     Reply with quote

Hi,

My compiler version is 5.076 and I'm working on a PIC16F1828.
I'm converting the following code from XC8 to CCS.
I want to read the data bits of a MCP4725 DAC device.

I want to convert the data of a two 8 bits to a numerical value of 16 bits.

In XC8 I could do this.
Code:
output = (upper8bits<<4) | (lower8bits>>4); // The 16-bit result we want to return.


For example, I set the MCP4725 with a value of 4095.
Reading the data gives a 12 bit value.
In this case, the upper 8 bits are 0xFF. The lower 8 bits are 0xF0.
I want to convert this to 0x0FFF (which is 4095 in decimal notation). So the upper bits are shifted 4 bits to the left, and the lower bits are shifted 4 bits to the right.

However, I get the wrong result in CCS.
I also tried the following methods:

Code:
rotate_left(&upper8bits, 1);
rotate right(&lower8bits, 1);


The second argument is the number of bytes.

Then I tried the following:
Code:
output = upper8bits + lower8bits;


This doesn't work.

Kind regards


+++++++++++++++++++++
Changed MCP4825 to MCP4725
to correct his typo.

- Forum Moderator
+++++++++++++++++++++
Ttelmah



Joined: 11 Mar 2010
Posts: 19538

View user's profile Send private message

PostPosted: Sat Nov 16, 2019 4:41 am     Reply with quote

Your original code will work, with one tiny change:
Code:

output = ((int16)upper8bits<<4) | (lower8bits>>4); // The 16-bit result we want to return.


The 'reason' is fundamental. CCS defaults to using the default integer size of
each processor. So on this chip, an 'int' is 'int8'. You can't rotate an int8
left four bits without losing 4 bits out the top. So it has to be told to do
the rotation on a 16bit value. This is done using the (int16) cast. XC8 defaults
to using 16bit integers.
temtronic



Joined: 01 Jul 2010
Posts: 9243
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sat Nov 16, 2019 12:14 pm     Reply with quote

hmm I can't find an MCP4825, is it really an MCP4725 ?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sat Nov 16, 2019 12:32 pm     Reply with quote

Yes I think it is.
nickdc



Joined: 19 Sep 2018
Posts: 15

View user's profile Send private message

PostPosted: Sat Nov 16, 2019 12:59 pm     Reply with quote

It is the MCP4725. I made a typo, sorry.
I will try the suggesting when I have access to my hardware.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sat Nov 16, 2019 1:14 pm     Reply with quote

I think the OP is over-thinking this. I just did a test of his method vs.
the most simple way of coding it. The simple way wins, in both speed
and code space.

His method:
Code:
output = ((int16)upper8bits<<4) | (lower8bits>>4);

vs. the simple method:
Code:
data = make16(upper8bits, lower8bits);
data >>= 4;

'data' is an int16.

If you put the printfs in, you get this output in MPLAB vs. 8.92 simulator:
Quote:
output= 0564
data= 0321

This shows both methods produce right-justified output.
But which one is more efficient ?

Using MPLAB vs. 8.92 Stopwatch with breakpoints, the execution time
of this line is 22 instruction cycles:
Code:
output = ((int16)upper8bits<<4) | (lower8bits>>4);


For the next two lines, the execution time is 14 cycles:
Code:
data = make16(upper8bits, lower8bits);
data >>= 4;



The amount of code generated for his method is:
Code:
... output = ((int16)upper8bits<<4) | (lower8bits>>4);
0003A:  CLRF   @@0C
0003C:  MOVFF  upper8bits,@@0B
00040:  RLCF   @@0B,F
00042:  RLCF   @@0C,F
00044:  RLCF   @@0B,F
00046:  RLCF   @@0C,F
00048:  RLCF   @@0B,F
0004A:  RLCF   @@0C,F
0004C:  RLCF   @@0B,F
0004E:  RLCF   @@0C,F
00050:  MOVLW  F0
00052:  ANDWF  @@0B,F
00054:  SWAPF  lower8bits,W
00056:  MOVWF  @00
00058:  MOVLW  0F
0005A:  ANDWF  @00,F
0005C:  MOVF   @00,W
0005E:  IORWF  @@0B,W
00060:  MOVWF  output
00062:  MOVFF  @@0C,output+1


But for the simple method, it is this:
Code:
.................... data = make16(upper8bits, lower8bits);
0006E:  MOVFF  upper8bits,data+1
00072:  MOVFF  lower8bits,data
.................... data >>= 4;
00076:  RRCF   data+1,F
00078:  RRCF   data,F
0007A:  RRCF   data+1,F
0007C:  RRCF   data,F
0007E:  RRCF   data+1,F
00080:  RRCF   data,F
00082:  RRCF   data+1,F
00084:  RRCF   data,F
00086:  MOVLW  0F
00088:  ANDWF  data+1,F


Test program:
Code:

#include <18F46K22.h>
#fuses INTRC_IO, NOWDT, BROWNOUT, PUT, NOPBADEN
#use delay(clock=4M)
#use rs232(baud=9600, UART1, ERRORS)

//======================================
void main()
{         
int16 output;
int16 data;
int8 upper8bits;
int8 lower8bits;

upper8bits = 0x56;
lower8bits = 0x40;
output = ((int16)upper8bits<<4) | (lower8bits>>4);
printf("output= %lx \r", output);

upper8bits = 0x32;
lower8bits = 0x10;
data = make16(upper8bits, lower8bits);
data >>= 4;
printf("data= %lx \r", data);

while(TRUE);
}

Ttelmah



Joined: 11 Mar 2010
Posts: 19538

View user's profile Send private message

PostPosted: Sat Nov 16, 2019 2:05 pm     Reply with quote

Worth just adding, that the 'simple' method, is just XC8 code.
The reason his second method didn't work, was that he was only
rotating one bit, when it needs four.
The optimised method is rather nice. Use the make8 instruction that
is nicely optimised, and then just rotate the entire word. Smile
nickdc



Joined: 19 Sep 2018
Posts: 15

View user's profile Send private message

PostPosted: Mon Nov 18, 2019 1:44 am     Reply with quote

When I try the optimized method, I get for 4095 (decimal) the following:

Quote:
upper8bits: 00ff
lower8bits: 00f0
output: 00ff


When I try:
Code:
output = ((int16)upper8bits<<4) | (lower8bits>>4);

I get:

Quote:
upper8bits: 00ff
lower8bits: 00f0
output: 00ff
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Nov 18, 2019 1:52 am     Reply with quote

Post a complete test program (as I did) that shows the problem.
nickdc



Joined: 19 Sep 2018
Posts: 15

View user's profile Send private message

PostPosted: Mon Nov 18, 2019 2:13 am     Reply with quote

This is my (shortened) program:
Code:

#include <16F1828.h>
#fuses HS,NOWDT,PROTECT,NOLVP,BROWNOUT
#use delay(clock=18.432M, CRYSTAL)  // xtal-frequency
#use rs232(STREAM = UART_Display, baud=115200,UART1,parity=N,bits=8, ERRORS)
#use i2c(master, scl=PIN_B6, sda=PIN_B4)
#define DEBUG
#include <stdbool.h>
#include <stdint.h>

#define MCP4725_CMD_WRITEDAC       (0x40)  // Writes data to the DAC
#define MCP4725_CMD_WRITEDACEEPROM (0x60)  // Writes data to the DAC and the EEPROM (persisting the assigned value after reset)

typedef struct {
    uint8_t address;
} mcp4725_dac_t;

mcp4725_dac_t dac;

void StdDacWrite(mcp4725_dac_t dac, uint16_t input, bool writeEeprom){
    char data = 0x00;
    i2c_start();
    i2c_write(0xCC);
    if (writeEeprom)
    {
        i2c_write(MCP4725_CMD_WRITEDACEEPROM);
    }
    else
    {
        i2c_write(MCP4725_CMD_WRITEDAC);
    }
    // /16 in 1 instruction
    data = (char)(input >> 4); // Upper data bits (D11.D10.D9.D8.D7.D6.D5.D4)
    i2c_write(data);
    data = (char)(input % 16) << 4; // Lower data bits (D3.D2.D1.D0.x.x.x.x)
    i2c_write(data);
    i2c_stop();
}

int16 StdDacReadDac(mcp4725_dac_t dac){
    int16 output;
    int8 upper8bits;
    int8 lower8bits;
   
#ifdef DEBUG
    char status;
    char output4 = 0x00;
    char output5 = 0x00;
#endif
    i2c_start();
    i2c_write(0xCD);
    //I2CAckBit();
#ifdef DEBUG
    status = i2c_read();
#else
    i2c_read();
#endif
    upper8bits = i2c_read();
    lower8bits = i2c_read();
    i2c_read();
    i2c_read();
    i2c_stop();
   
#ifdef DEBUG
    printf("status: %x\r\n", status);
    printf("upper8bits: %4x\r\n", upper8bits);
    printf("lower8bits: %4x\r\n", lower8bits);
    printf("output4: %x\r\n", output4);
    printf("output5: %x\r\n", output5);
#endif
    //rotate_left(&upper8bits,4);
    //rotate_right(&lower8bits,4);
    printf("upper8bits: %4x\r\n", upper8bits);
    printf("lower8bits: %4x\r\n", lower8bits);
    output = ((int16)upper8bits<<4) | (lower8bits>>4); // The 16-bit result we want to return.
//    output = make16(upper8bits, lower8bits);
//    output >>= 4;
    printf("output: %4x\r\n", output);
    //printf("output: %d\r\n", output);
    return output;
}

int16 ApplicationReadVoltage(mcp4725_dac_t dac){
    return StdDacReadDac(dac);
}

/* Set value via I2C. */
void ApplicationSetVoltage(mcp4725_dac_t dac, uint16_t input, bool writeEEPROM){
    StdDacWrite(dac, input, writeEEPROM);
}

void main(void) {
    printf("start\r\n");
    ApplicationSetVoltage(dac, 4095, false);
    ApplicationReadVoltage(dac);
    while(TRUE){

    }
    return;
}



EDIT:

It seems to have been an error with the printf formatter. When I use %lx instead of %4x, I get the correct output printed.


Last edited by nickdc on Mon Nov 18, 2019 4:41 am; edited 1 time in total
Ttelmah



Joined: 11 Mar 2010
Posts: 19538

View user's profile Send private message

PostPosted: Mon Nov 18, 2019 2:43 am     Reply with quote

You would. %x, says to print an 8bit integer. The 'L' says instead to print
a 16 or 32bit integer. Smile
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