Jump to content
Sign in to follow this  
abecedarian

Manifold absolute pressure sensing

Recommended Posts

Decided to start a project based discussion regarding the BP I posted http://forum.43oh.com/topic/4301-manifold-absolute-pressure-sensing/ so as to not clutter that up.

 

For those that haven't visited that, here's a re-cap:

MCU samples an MPX4250A absolute pressure sensor, takes the reading and looks up a value from a table, and sends that to a DAC for output. It's actually two DACs though so there are possibly two values to read and send. There's an SPI eeprom for storing the values and the DAC's are set over SPI as well.

 

There will be software that interfaces to it, at least for the stand-alone version, that allows for altering the tables therefore making the unit able to read absolute pressure and output arbitrary voltages based on the readings.

 

There will be two tables, more appropriately I guess I should call them arrays, with 256 entries. Not considering the accuracy of the MPX sensor, ADC or the DAC, considering 5 volts, that's a resolution of approximately 0.02 volts per cell / entry. Good enough, I think, for my purposes.

 

Eagle board / schematics can be found at the link above.

Share this post


Link to post
Share on other sites

I was thinking about how best to access the data for the ADC / DAC translation. 

 

It's probably fast enough, but doing an ADC conversion, translating that to the appropriate location in the eeprom, retrieving that over SPI then sending it out to the DAC over SPI seems like a lot of overhead. If the MCU could do most everything from memory, that would reduce latency a bit.

 

Problem is the G2553 only has 512 bytes RAM so can't store two, 256 unsigned integer tables.

 

I found, at least with Energia, I can define two const unsigned int arrays with 256 entries and pre-populate those with a value of 65535, then in "setup" iterate over those, reading each one and outputting to Serial, and get the compiler to include those in program memory instead of RAM.

 

Since they're allocated in program memory instead of RAM, which amounts to flash, I wonder if it would be possible to alter the values from with the program?

I'd think getting the pointer to memory location and write a new value to that location would work? Or does MSP have some mechanism that prevents that?

Share this post


Link to post
Share on other sites

The thought was that on power up, the unit could do its thing, and read from the eeprom, replacing any data in the two tables using pointers and such.

 

If the first value read was 65535, that is obviously an incorrect value since at 0 kPa, maximum vacuum, it's not possible for the sensor to output anything near 65535 since that is the maximum pressure.

 

Also, the string of 65535 sent out via serial could be an indicator to the tuning software that the unit was just powered up... maybe add a little to the output, like output a 0, 65535, 0 , 65535 to signal when the unit is done initializing?

Share this post


Link to post
Share on other sites

It is possible to write to the main program flash, doing so requires first erasing the "page" and then writing to it with the page unlocked (look elsewhere and in TI's samples for flash writing semantics, I think there is a flash writer library for Energia too)... The tricky part may be to make sure the compiler declares these const arrays on an even page boundary.  If I'm not mistaken, the pages are 512-bytes large.  So going in to change 1 value won't be possible; but erasing the whole page and starting anew, filling the contents as you generate or discover them, is possible.  Only 10,000 rewrite cycles guaranteed.  But guaranteeing they exist on an even page boundary would require a custom linker script I think, with the segment declared as its own section and then your program declares the const unsigned int arrays as part of that section.

 

FRAM chips offer you the kind of free-form writability that you might be thinking.

Share this post


Link to post
Share on other sites

And pardon me for a moment, I'm going to use an MCP4922, 12 bit DAC for prototyping purposes. If it works well, it might be in the final product.

If nothing else, it'll help me get some things figured out, and that Microchip sent me 4 is a plus.

Share this post


Link to post
Share on other sites

Okay, probably a dumb question but, looking at the MCP4922, which is a 12 bit DAC, it takes a 16 bit word- 4 bit command and 12 bit value, in order to do something. I'm confused about how to do this.

 

As the DAC is 12 bits, and there is no 12 bit data type, I'm thinking store the 12 bit value as an unsigned integer and take the 4 bit command and cast it to 16 bit unsigned integer and shift left 12 bits.

 

Therefore a bitwise "OR" of the two should give a 16 bit word that contains the 4 bit command and the 12 bit value, correct?

Share this post


Link to post
Share on other sites

Okay again.... Since it's a 12 bit DAC I'm experimenting with and it expects 16 bit words, I decided on this:

 

const unsigned int DACB = 37268;                   // 16th bit = 1 = output on DAC B
const unsigned int DACA = 0;                       // 16th bit = 0 = output on DAC A
const unsigned int BUFF = 16384;                   // 15th bit = 1 = input register buffered
const unsigned int UNBUFF = 0;                     // 15th bit = 0 = input register unbuffered
const unsigned int GAINX1 = 8192;                  // 14th bit = 1 = Gain = 1 x Vref
const unsigned int GAINX2 = 0;                     // 14th bit = 0 = Gain = 2 x Vref
const unsigned int NOTSHDN = 4096;                 // 13th bit = 1 = Output is now active, in case it was shut down
const unsigned int SHDN = 0;                       // 13th bit = 0 = Output is inactive / shut down
Might be a waste of memory but they are values I can bitwise "OR" into the target.

 

For instance, I may have a routine where I want to set DACB to output d2Out, at 1x gain, and have that DAC turned on in case it was shut down.

I could:

unsigned int out = DACB | GAINX1 | NOTSHDN | d2Out;
SPI.write (out);

Share this post


Link to post
Share on other sites

Thinking some more about what I mentioned previously, there should be some error detection done so that the MCU knows if the eeprom has been programmed by the PC software. If that hasn't been done, the DAC should not be turned on in order to prevent damage to the vehicle.

Regarding the 4922 eeprom. Since the data type being stored in eeprom is 16 bit unsigned integer, and the DAC is 12 bit, the values I mentioned above- the control word, could be written together with the output value. The 16 bits read from the eeprom could be written to the DAC as is- DAC channel and such already set up.

To clarify, the person setting up the unit would use the PC software to program the MCU and if they chose to utilize only one of the DAC's, the data stored in eeprom would reflect a DAC shut down and when the MCU read values with the SHDN bit set to 0 would skip writing anything to the DAC for that. Not sure I like it but would work. Preferably, the eeprom would store data reflecting which DAC is in use / programmed and skip any unnecessary SPI hits to keep latency to a minimum, though predictable hits might smooth things out and not require artificial delays, or incur unnecessary delays. And who's to say the user didn't disable the DAC for some reason and hasn't hacked things to enable it at some pressure. ... second guessing myself again.

 

Maybe need to hard-code the GAIN bit into the tuning software as VREF is not something the user can change easily... same with buffering- it's write some values then raise CS so no worrying about LDAC. SHDN / NOTSHDN handled in the tuning software so no need there.

 

Thanks much everyone! You helped me trim a few bytes off the code. :D

Share this post


Link to post
Share on other sites

Using @@spirilis Arduino eeprom library: https://bitbucket.org/spirilis/spieep. Now I'm able to talk to the eeprom without much fuss and the library has quite impressive functions. Maybe there should be an official port for Energia? Hint, hint. ;-)

 

So far, only one small issue- the library uses 16 bit integers to create the eeprom object so giving it an eeprom size of 65536 or greater throws an overflow error in Energia. Modifying the library slightly, and passing it 65535, gets around the error for eeprom up to 65536 bytes, at least as far as I can tell. Alternatively, the 'totalsize' variable could be changed to unsigned long, and should be for larger eeprom like the 25AA1024.

 

SPIEEP::SPIEEP(int addrwidth, int pagesize, int totalsize) {
_cspin = -1;
_addrwidth = addrwidth / 8;
_pagesize = pagesize;                    
_numpages = totalsize / pagesize;        // by abecedarian: comment this out- it is not used elsewhere
_highestaddr = totalsize - 1;            // by abecedarian: remove "- 1" and use 65535 for total size, 
if (_addrwidth == 1 && totalsize == 512) // Is it a 25(AA|LC)040 512-byte chip?
// these require special support where they use 8-bit addresses but the 9th bit is included
// inside the instruction.
_is_25LC040 = 1;
else
_is_25LC040 = 0;
}
Thanks @@spirilis. :grin:

Share this post


Link to post
Share on other sites

Yeah I was using a 32KB eeprom when I developed that, but what's funnier is I used "int" rather than "unsigned int"... you can tell it was one of my first Arduino library efforts ;)

 

Sent from my Galaxy Note II with Tapatalk 4

 

 

Share this post


Link to post
Share on other sites

@@spirilis - I still think you should do an Energia port. :thumbup:

 

 

Anyhow....

 

Does this look right for converting the desired output voltage to the appropriate value to send to the DAC?

Variable "desiredOut" is the result from an equation relating kPa to the voltage the sensor should output, and was constrained to 0.10 - 4.9v.

 

dac = int((desiredOut/5.0)*4096);

 

I've ran a program on the G2553 that does the calculations for both sensors and the output appears to be correct.

The attachments are a copy / paste of the output the MSP sent over serial to the PC, and the Energia ino used to generate it.

 

Psensor_setup.txt

MAP_EMULATE_4922_b.ino

Share this post


Link to post
Share on other sites

As noted in the BP topic linked in the opening post, I had been considering a 40 pin BP so it could be used with G2 and other LaunchPads. When it was realized that the G2 was the only LP with the ADC reference broken out to the headers, that plan changed. Now, the focus is going to be on a BP used with the F5529LP.

 

I think the change is appropriate considering that the G2 is only $3 less than the F5529, and the latter is equipped with USB. USB functionality would have been an add-on for the G2, increasing costs well above the $3 difference between the two LPs, and considering the external eeprom the G2 would require will not be necessary, there's a reduction in cost that will help offset the cost of the now necessary external 2 channel SPI ADC. More information about the BP will be posted in that topic.

 

More to come shortly.

Share this post


Link to post
Share on other sites

With the F5529LP, what I'd like to do is implement MSC and CDC devices.

 

Before I go there though, I'd like to explain how I think the unit should operate normally.

 

"Tune" configurations are stored in flash. It is basically two arrays of 256 entries, each array correlating an ADC read value to a DAC output. The ADC will have a little over-sampling, and bit shifting, to smooth the readings down to 8 bits, and that will be the index to the array. When the unit powers up, it will copy the stored tune from flash to sram and uses the sram copy during operation.

 

This provides for 'live' tuning since any alterations to the tune will affect sram, as that can be modified on the fly without issue. Once a 'live' tune is satisfactory, it will need to be committed to flash. Writing to flash has issues since it will interrupt the processor and will likely cause issues with the system if that is done 'live'.

 

Here's where the MSC device comes in.

 

MSC would present a small file system to the OS, where the user or tuning software could drop files. These files would be 'tuning' files. On the next power-on, the unit would detect the file is present and copy it to flash, then delete the file. This would provide a mechanism where the user could save tunes from the tuning software and restore a tune if an altered one didn't perform correctly. So the presence of the file on power up initiates an update, and the lack of file indicates everything is fine and start up using flash. A file written to the MSC device while it is running would be ignored until the next power cycle.

 

I would eventually like to use MSC to provide for firmware updates as well, where the user can drop the update on the device and again, after the next power cycle, it would read the update in and update the firmware in similar fashion to a bootstrap loader. My goal is to make firmware updates as painless as possible, not requiring any special programs and such. But I see that as an option in the not-so-near future. ;-)

 

 

 

The CDC device would be a Virtual COM port used by the tuning software to receive 'live' updates from the unit regarding ADC and DAC values, as in what was read and what was sent, and adjust the current tune as well as read and save the current tune. This would permit someone to read the tune and save it if they weren't the one who made it, so that things could be restored later if something goes wrong. I also plan on implementing the use of the F5529's temperature sensor in order to provide some temperature compensation. See, the ADC12 on the chip isn't going to be a total loss. :grin:

 

 

As always, comments are welcome.

Share this post


Link to post
Share on other sites

Thinking out loud.

 

I suppose an alternative could be, since MSC contents are inherently stored in flash, to keep the tune on the MSC and copy it to SRAM each time the unit boots up, and if the tune is modified by the tuning software, copy that back to the MSC on demand. It does seem to be redundant, copying MSC to flash, when it's already flash.

 

The firmware could probably be somewhat self-initializing, as in if there is no "tune.sys" file on the MSC it would automatically create the file using a simple equation correlating 0v=0kPa to 5v=250kPa using 256 steps, thus making that the 'default' configuration.

 

So I see two files necessary: "config.sys" and "tune.sys". The former being a small file dictating which outputs are enabled, in a bit-wise manner: "0" = both outputs are disabled; "1" = output1 is enabled, output2 is disabled; "2" = output2 is enabled, output 1 is disabled; "3" = output1 and output2 are enabled. The latter being the two arrays used to correlate ADC to DAC. Doing it this way, I feel, would provide for possible future features to be enabled using other bits in the byte as flags. "3" is redundant as I'd likely do something like:

 

If ((config && 1) = 1) then output1;
if ((config && 2) = 2) then output2;
((config && 3) = 3) is somewhat redundant in that context, as both previous comparisons / conditions would have been satisfied.

 

The latter file would be the kPa : volt output correlation.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

×
×
  • Create New...