|
|
View previous topic :: View next topic |
Author |
Message |
nickdc
Joined: 19 Sep 2018 Posts: 15
|
Reading MCP4725, rotating and concatenating two bytes |
Posted: Sat Nov 16, 2019 3:40 am |
|
|
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
|
|
Posted: Sat Nov 16, 2019 4:41 am |
|
|
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
|
|
Posted: Sat Nov 16, 2019 12:14 pm |
|
|
hmm I can't find an MCP4825, is it really an MCP4725 ? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Nov 16, 2019 12:32 pm |
|
|
Yes I think it is. |
|
|
nickdc
Joined: 19 Sep 2018 Posts: 15
|
|
Posted: Sat Nov 16, 2019 12:59 pm |
|
|
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
|
|
Posted: Sat Nov 16, 2019 1:14 pm |
|
|
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
|
|
Posted: Sat Nov 16, 2019 2:05 pm |
|
|
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. |
|
|
nickdc
Joined: 19 Sep 2018 Posts: 15
|
|
Posted: Mon Nov 18, 2019 1:44 am |
|
|
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
|
|
Posted: Mon Nov 18, 2019 1:52 am |
|
|
Post a complete test program (as I did) that shows the problem. |
|
|
nickdc
Joined: 19 Sep 2018 Posts: 15
|
|
Posted: Mon Nov 18, 2019 2:13 am |
|
|
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
|
|
Posted: Mon Nov 18, 2019 2:43 am |
|
|
You would. %x, says to print an 8bit integer. The 'L' says instead to print
a 16 or 32bit integer. |
|
|
|
|
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
|