|
|
View previous topic :: View next topic |
Author |
Message |
matrixofdynamism
Joined: 06 Dec 2010 Posts: 25
|
|
Posted: Mon Apr 04, 2016 5:52 am |
|
|
I have used bitfields in the past but only on rare occasions. I have not tried to fully understand how to use them as I was programming in C++ and VHDL. In my present situation though I am trying to figure out every single detail that I consider relevant to bitfields. I have habit of taking notes. When I come across a problem, I try to understand all aspects of it, answer all questions by asking real people or forums or reading books or application notes that then write it down in my notebook.
I wanted to write a program where I can access SFRs like variables. That is solved by using struct, getenv() and #byte. Then I wanted to be able to access fields in an SFR like field in struct, that is solved by using bitfields. However, there are a few more questions that must be answered which I have posted later in this thread, and for them I am going to do some experiments today as another person has advised.
I have an 8-bit ADC. It takes a 16 bit word as input. The first 4 bits are programming bits then come 8 data bits, these 8 bits are clearly split between the upper and lower byte. Then we have 4 bits of don't care. This can be created as a bitfield, or it can be implemented using bit-shift and logic operation.
I shall also have to write more code which can be simplified with bit fields and for all this I am trying to fully understand how to use bitfields in CCS PIC C compiler so I know what I am doing. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9241 Location: Greensville,Ontario
|
|
Posted: Mon Apr 04, 2016 6:48 am |
|
|
re:
I have an 8-bit ADC. It takes a 16 bit word as input. The first 4 bits are programming bits then come 8 data bits, these 8 bits are clearly split between the upper and lower byte. Then we have 4 bits of don't care. This can be created as a bitfield, or it can be implemented using bit-shift and logic operation.
The easy solution is to rearrange the 16 bit word as
4 bits of programming bits
4 bits of don't care
8 bits of ADC data
this way the ADC data is 'whole',can be accessed as a byte, faster.
This same regrouping helps with 'bit' data as well. Group 8 similar bits into a byte, then 8 bit integers,then 16 bit words. Usually bits are used as 'flags' so grabbing a 'byte' of flags for testing or configuring and tends to be easier on the eyes to read them.
As the programmer you have( or should have) control over the format of the data.
Jay |
|
|
matrixofdynamism
Joined: 06 Dec 2010 Posts: 25
|
|
Posted: Mon Apr 04, 2016 7:13 am |
|
|
The DAC is MCP4801. The don't care bits must be after the data so I guess I shall have to put them this way in the struct also. See Figure 5-3 in http://ww1.microchip.com/downloads/en/DeviceDoc/22244B.pdf#page=23
Basically, the data containing struct which has bitfields shall be directly written into the SSPBUF for SPI write, one byte at a time.
By the way, should the bit field members be declared as int8 or unsigned char or something else? I am sure that a convention exists for the CCS PIC C Compiler that is perhaps not portable.[/img] |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Mon Apr 04, 2016 7:29 am |
|
|
It's a DAC, not an ADC, of course.
That sort of arrangement is common. Its done so that you can treat all three versions, 8, 10, and 12 bit the same way, i.e. as if they were 12 bit, and deal with the data you send as an int16. That simplifies writing a driver as you can have one common driver for all versions of the family. The 10 and 8 bit chips simply ignore the two or four "don't care" bits.
Of course the compiler has to do much the same bit shift and logic operations in bitfields as you would do if you constructed the two bytes yourself. It'd do it less efficently - giving bigger and slower code - than we humans can. This is a pretty trival example that would be much simpler, smaller and faster the shift way. That would be my first and probably only approach to this problem.
EDIT: Indeed, it is how I approach the problem for the very similar MCP4822, which is essentially two MCP4812s in a single package.
Code: | void write_mcp4822(int16 DAC_SELECT, int16 value_1, int16 value_2)
{
// Prepare the first value
if(value_1 > 0x0FFF) //Limit value of DAC A value with no rollover
{
value_1 = 0x0FFF;
}
// Set control bits
bit_clear(value_1, 15); // Write to DAC A
bit_clear(value_1, 13); // Output gain = 2
bit_set(value_1, 12); // Output enabled
//write the first value. The MCP4822 treats its two
// channels effectively as two DACS. We have to issue TWO
// SPI sequences. We cannot send one long one with both
// sets of data.
output_low(DAC_SELECT); //select DAC IC /CS
spi_write(make8(value_1,1)); //write upper byte
spi_write(make8(value_1,0)); //write lower byte
output_high(DAC_SELECT); //unselect DAC /CS
// Prepare the second
if(value_2 > 0x0FFF) //Limit value of DAC B value with no rollover
{
value_2 = 0x0FFF;
}
// Set control bits
bit_set(value_2, 15); // Write to DAC B
bit_clear(value_2, 13); // Output gain = 2
bit_set(value_2, 12); // Output enabled
output_low(DAC_SELECT); //select DAC IC /CS
spi_write(make8(value_2,1)); //write upper byte
spi_write(make8(value_2,0)); //write lower byte
output_high(DAC_SELECT); //unselect DAC /CS
// Latch both values onto the analogue outputs
output_low(latch_dac);
// At 10MHz there is sufficient time between instructions to
// meet the MCP4822's timing requirements without any additional
// delays. The analogue output changed when we drove the latch
// low. All we need to do now is bring it high again.
// That was true at 10MHz, but not at 40MHz! So we have to add a few NOPs
// to ensure correct timing. 1 "wait state" gives 200ns at 40MHz, or 500ns at 10MHz
delay_cycles(1);
output_high(latch_dac);
} |
|
|
|
matrixofdynamism
Joined: 06 Dec 2010 Posts: 25
|
|
Posted: Mon Apr 04, 2016 5:17 pm |
|
|
I got the DAC to work finally. However, I was held for a while. This is my first time using SPI on the PIC in actuality. The DAC would not do anything and after looking at the waveforms by sending 0x01 and 0x80, 0x20 and 0x40, I realized that the data was changing at the rising edge of clock and thus expected to be latched at the falling edge. This was opposite of what was given in the datasheet for the DAC.
The DAC mentioned mode 00 and mode 11 as valid SPI modes. I did not know what that even means but I came across description of these modes by chance in the PIC datasheet I have printed out. It gave the values for CKP and CKE that correspond to each mode. I used the CCS PIC C debugger through the ICD-U64 to read the SFRs. It was clear that the values of these bits in the SSP1CON1 and SSP1STAT as existed in the PIC do not give me mode 00 or mode 11. Thus, I eventually used assembly instructions to set and clear the CKP and CKE bits accordingly.
How am I supposed to set a specific mode of SPI operation using the setup_spi command? What does SPI_H_to_L and SPI_L_to_H mean?
The SPI bus modes are described here:
http://ww1.microchip.com/downloads/en/DeviceDoc/39960d.pdf#page=289 |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Apr 04, 2016 11:03 pm |
|
|
matrixofdynamism wrote: |
How am I supposed to set a specific mode of SPI operation using the
setup_spi command? What does SPI_H_to_L and SPI_L_to_H mean?
|
Use the #define statements for the SPI modes in the following post.
Put them above main():
http://www.ccsinfo.com/forum/viewtopic.php?t=47614&start=2 |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19535
|
|
Posted: Tue Apr 05, 2016 12:18 am |
|
|
As a comment though, if you are new to CCS SPI, then really don't use setup_spi....
This is the 'old' SPI interface command. The new (and current) way to do SPI configuration, is #use spi. #use spi, 'knows' SPI mode numbers directly, and is a much more powerful and flexible way to work. For instance it allows you to directly send 8bit, 16bit, and 32bit values in a single command. More importantly though it allows you to have multiple SPI interfaces accessed by name. It's a much tidier solution all round. |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Tue Apr 05, 2016 1:39 am |
|
|
Ttelmah wrote: | As a comment though, if you are new to CCS SPI, then really don't use setup_spi....
This is the 'old' SPI interface command. The new (and current) way to do SPI configuration, is #use spi. #use spi, 'knows' SPI mode numbers directly, and is a much more powerful and flexible way to work. |
Interesting to know that what at first appeared to be an interesting, but somewhat arcane, problem with bitfield syntax and semantics turns out to have actually been about the much commoner and straightforward issue of getting SPI to work :-( It's nice to be able to solve the real problem :-|
It also shows the pitfall that is reaching for assembler and direct SFR access before bothering to understand how the hardware works and compiler can do.
PS: My code is old and used the old setup_spi way of doing SPI. The bit_clears are also redundant, as limiting the value ensures the upper, control bits are always zero. They are retained for clarity of function and readability. |
|
|
matrixofdynamism
Joined: 06 Dec 2010 Posts: 25
|
|
Posted: Tue Apr 05, 2016 1:44 am |
|
|
hmm, I thought that the #spi was for "software SPI" i.e bit-banging as it is called and setup_spi() was for hardware spi. So that is not true?
RF_Developer, if the bit_clear and I supposed by that extension that bit_set are redundant or outdated, what is the newer method to do this? The reason I went for assembler is that it will enable understanding the PIC hardware internally. Yes, it is true that I have written the first 2 assembly instructions of my life last night which are BCF and BSF.
Last edited by matrixofdynamism on Tue Apr 05, 2016 1:46 am; edited 1 time in total |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Tue Apr 05, 2016 1:44 am |
|
|
Read the CCS manual. What does it say? |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Tue Apr 05, 2016 7:07 am |
|
|
matrixofdynamism wrote: | hmm, I thought that the #spi was for "software SPI" i.e bit-banging as it is called and setup_spi() was for hardware spi. So that is not true? |
Not quite true. setup_spi(), spi_write() and spi_read() were the old way and could only be used with spi hardware. #use spi and spi_xfer() is the newer, and preferred for new code, way and provides software SPI support as well as support for the hardware, if present.
My code was written over five years ago. It could be used with newer #use spi method, for either hard or soft SPI, simply by changing the spi_write calls to equivalent spi_xfer calls.
Quote: | if the bit_clear and I supposed by that extension that bit_set are redundant or outdated, what is the newer method to do this? |
No, go back and re-read what I wrote. I said that in my code the bit_clear()s, were redundant as those bits were already known to be zero due to code before it. As the bits were known to be zero, there's no point in setting them to zero, but plenty of point to set bits to one if that's what's needed. So I could have deleted the bit_clears, but the bit_sets must stay!
The routines, bit_clear() and bit_set(), which code to BCF and BSF instructions in 18 series PICs are not in any sense redundant nor superceded. There is no "newer" way to do it. EDITED TO ADD: note that these are NOT standard C, they are CCS C specific extensions that target hardware features of the PIC processor. They are NOT portable to other C compilers of hardware targets, though similar facilities may well be available in many embedded Cs. |
|
|
|
|
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
|