Skip to main content
Arduino

Return to Question

Bumped by Community user
Bumped by Community user
Bumped by Community user
Bumped by Community user
added 359 characters in body
Source Link

Is it the fact that the arduino is a little endian and I'm relating that to a SPI that transmits MSB first? From the various 64b words I've gotten back, that also doesn't appear to be the case, given the last byte also changes. This is why I'm kind of stumped

Also, per the datasheet there are some fixed (CB) bits and wouldthe SPI fault bits that should be giving some insight into the health of the current SPI frame. Both of these are giving me issues as well, which is further pointing me at that I've got something messed up with my SPI communication.

All reasons I'd appreciate a littlesome help! Below are some "outputs" from my current code just as a sample for what I'm talking about.

Is it the fact that the arduino is a little endian and I'm relating that to a SPI that transmits MSB first? From the various 64b words I've gotten back, that also doesn't appear to be the case, given the last byte also changes. This is why I'm kind of stumped and would appreciate a little help!

Is it the fact that the arduino is a little endian and I'm relating that to a SPI that transmits MSB first? From the various 64b words I've gotten back, that also doesn't appear to be the case, given the last byte also changes.

Also, per the datasheet there are some fixed (CB) bits and the SPI fault bits that should be giving some insight into the health of the current SPI frame. Both of these are giving me issues as well, which is further pointing me at that I've got something messed up with my SPI communication.

All reasons I'd appreciate some help! Below are some "outputs" from my current code just as a sample for what I'm talking about.

Source Link

L9780 and SPI communication

I'm working on a program to interface with a development board I spun for an L9780 - wideband oxygen controller IC. At this point, I'm trying to get a consistent "status" read back but continue to get some unexpected results that I'll explain below. This is the first "real" time I'm trying to write the SPI sequence for a chip from scratch, which is why I'd appreciate a sanity check!

The first question/verification I had was the SPI mode/setup. Searching around it looks like per the datasheet my clock is idle-low and the first data assertion (on SI) happens prior to the clock edge going high. This should correspond to a MODE0. Section 6.3 lists it as MSB first. The SPI timing table also lists 8MHz for the transfer rate; all the above should give me my config, correct?

My second question/verification was my use of the "SPI.transfer()" function. I made my way through this thread and understand the syntax behind it, so I think that part is ok.

Section 6.3.1 talks about the "REG" bit which is what's used to latch if the next SO frame contains the input reg, or the current "status" reg. This is why in my "get_status" function I'm sending out the request, and then doing another SPI.transfer (via the function) to read the result. Is this correct?

The reason I think I'm having issues is that for the status reg, the MSB is an ignored bit and then 3 version bits. Intermittently, when using my current code to test, I'm getting a change from a dec(1) value to a dec(2) value. This obviously isn't right, so while it appears I'm able to "communicate" in some form with the chip I'm guessing my formatting or byte order is FUBAR somewhere.

Is it the fact that the arduino is a little endian and I'm relating that to a SPI that transmits MSB first? From the various 64b words I've gotten back, that also doesn't appear to be the case, given the last byte also changes. This is why I'm kind of stumped and would appreciate a little help!

  • SI register on startup (no setting transfer, nothing)

    • 0x4503458300C2CD31
    • 0x450345A300E26E32
    • 0x450345A300E27732
  • SI register after "send H/W config to L9780"

    • 0x370045A30002F933
    • 0x370045A30082FA33
  • status register on startup (no setting transfer, nothing)

    • 0x450345A300024632
    • Same result, multiple times
  • status register after "send H/W config to L9780"

    • 0x380045A3FFE1FA33
    • 0x380045A300E2FA33
    • 0x370045A300C2F933
  • Status register after heatup and "enable VCCS" and "enable stgINRC"

    • 0x1A031AA3001AFA33
    • 0x0C030CA3007AFA33
    • 0x1A0319A300FAFA33
    • 0x150315A3009AFA33

L9780 datasheet

/* Program is taken from the development firmware but simplified
 * to menu actions for preliminary debug.
 * 
 * NOTES
 * -------------
 * -HTR PWM output from uC seems to be inverse. When applying a 
 * 15% duty, the heater draw is higher than 85% duty
 */
//*****includes
#include <SPI.h>
//*****general defines and data
#define serial_baud 9600 //serial baudrate
#define L9780_SPI_SPD 8000000 //SPI Frequency (per L9780 timing diagram)
#define L9780_SPI_ORDR MSBFIRST //define SPI order as MSB first (per L9780 timing diagram)
#define L9780_SPI_MODE SPI_MODE0 //define SPI mode, clock Idle LOW, first CMD sent w/o SCK (per L9780 timing diagram)
#define L9780_SO_SI true //used for "get status" - put the input (SI) register in SO
#define L9780_SO_STAT false //used for "Get status" - put the status register in SO
//pn_SPI0_MOSI 11 //!pinDef: SPI0 master out slave in
//pn_SPI0_MISO 12 //!pinDef: SPI0 master in slave out
//pn_SPI0_SCK 13 //!pinDef: SPI0 clock
#define pn_L9780_CS 10 //!pinDef: chip select for L9780
#define pn_htr_out 9 //!pinDef: manual heater control output
//*****L9780 specific data
#define L9780_rx_reg 0x0800000000000000 //mask to get back the L9780 input register - bitOR
#define L9780_status_reg 0xF7FFFFFFFFFFFFFF //mask to get back the status register - bitAND
#define L9780_VCCS_en 0x0040000000000000 //mask to enable operator - bitOR
#define L9780_STGINRC_en 0x0200000000000000 //mask to enable short to gnd on INRC - bitOR
#define LSU49_start_CFG 0x00040F18192A8040 //LSU 4.9 start config - non-synchronous mode
/* Config bit definitions:
 * b63-60 = 0; not used
 * b59 = REG; set appropriately when transmitting or receiving
 * b58 = 0; INRC pull-down (try initially disabled)
 * b57 = 0; INRC short to ground enable (disable on start)
 * b56 = 0; INRC gain
 * b55 = 0; tag resistor network switch (ch1)
 * b54 = 0; VCCS enable (disable on start)
 * b53 = 0; VCCS output ch (ch1)
 * b52 = 0; VCCS pull-down (try initially disabled)
 * b51 = 0; compensation network (chA)
 * b50 = 1; VCCS voltage clamp enable
 * b49 = 0; VCCS voltage clamp switch (ch1)
 * b48 = 0; VCCS voltage clamp symetry (symetric)
 * b47 = 0; fault clear (don't clear any faults)
 * b46-43 = 0001; purge current (-14uA) (taken from L9780 test docs)
 * b42-40 = 111; FV out gain (12) (taken from L9780 test docs)
 * b39-34 = 000110;VCCS capacitance (assumed Rtag ~130 ohm)
 * b33-32 = 00; measurement clock period 4MHz
 * b31 = 0; heater short to battery threshold (250mV)
 * b30-24 = 0011001; RCT1 switch time pulse duration (taken from L9780 test docs)
 * b23 = 0; operation mode (free-running)
 * b22-16 = 0101010; RCT1 bandgap switch pulse duration (taken from L9780 test docs)
 * b15-14 = 10; SPI confirmation bits - always 0b10
 * b13 = 0; not used
 * b12-11 = 00; heater short to battery fault time (80 Tosc)
 * b10-8 = 000; INRC switch time pulse duration (taken from L9780 test docs)
 * b7 = 0; protection FET ch2 (disabled)
 * b6 = 1; protection FET ch1 (enabled)
 * b5-0 = 0; not used
 */
void setup() {
 Serial.print(F("Initializing uC.............."));
 Serial.begin(serial_baud); //start serial. Needed for more than just debug
 
 pinMode(pn_L9780_CS, OUTPUT); // set the CS pin as an output
 digitalWrite(pn_L9780_CS, HIGH); // set the CS pin to HIGH (off) 
 SPI.begin(); // initialize the SPI -> library begin function sets output pins
 
 pinMode(pn_htr_out, OUTPUT); // heater PWM output
 digitalWrite(pn_htr_out, HIGH); // turn htr PWM off
 Serial.println(F("Init Complete!"));
 //****display menu
 Serial.println(F("Menu Options"));
 Serial.println(F("--------------------------------------------------------------"));
 Serial.println(F("1) Init - Send H/W config command to L9780"));
 Serial.println(F("2) Init - Heatup WBO2 sensor"));
 Serial.println(F("3) L9780 - Enable VCCS (start operation)"));
 Serial.println(F("4) L9780 - Enable stgINRC (start closed-loop L9780 control)"));
 Serial.println(F("6) L9780 - Get status register")); 
 //****end display menu
}
void loop() {
 while (Serial.available() == false){} //wait for user input
 int menu_choice = Serial.parseInt(SKIP_ALL); //get user input
 Serial.println(menu_choice);
 char c[150]; //char string for menu outputs
 switch (menu_choice){
 case 1:
 L9780_SPI_xfr(LSU49_start_CFG); //set initial config values over SPI
 break;
 case 2:
 heatup_WB02(); //heat-up sequence
 break;
 case 3:
 L9780_SPI_xfr(LSU49_start_CFG | L9780_VCCS_en); //enable VCCS (start operating)
 break;
 case 4:
 L9780_SPI_xfr(LSU49_start_CFG | L9780_STGINRC_en);//enable INRCSTG once started
 break;
 case 5:
 {uint64_t data = L9780_get_status(L9780_SO_STAT); //get current status output
 Serial.print(F("Status Reg (64b): 0x")); SerialPrint_u64(data, true);
 }break;
 default:
 Serial.println(F("Input not recognized, please enter a valid number"));
 break;
 }
 Serial.println(F("--------------------------------------------------------------"));//bookend lines
}
/* FUNC: Serial Print unsigned 64b value
 * DESC: Fucntion prints an unsigned 64b wide value
 * ARGS: v - value to print
 * nl - true/false to print a new line
 * RETN: none
 */
void SerialPrint_u64(uint64_t v, bool nl){
 char c[] = "00000000"; //temp byte to print
 sprintf(c,"%08lX", (v>>32)); Serial.print(c);
 sprintf(c,"%08lX", v); Serial.print(c);
 if(nl){Serial.println();} //if selected, print newline
 return;
}
/* FUNC: WBO2 sensor heatup
 * DESC: Fucntion called on sensor initialization
 * and controlls the initial heatup cycle, including
 * the condensation and ramp phase.
 * ARGS: none
 * RETN: none
 * NOTES: PWM out from L780 is inverse from arduino output
 */
void heatup_WB02(){
 Serial.println(F("-----Starting Sensor Heatup----"));
 int htr_pwm = 211;
 analogWrite(pn_htr_out, htr_pwm); //condensation stage
 Serial.println("---Condensation Phase");
 Serial.print("HTR PWM %: ");Serial.println(htr_pwm*20/51);
 delay(11000); //simplified wait for ~20s total for condensation stage to be done
 Serial.println("---Condensation Phase End");
 htr_pwm = 76; //start ramp phase, start at 70% duty (approx 8.4V)
 while(htr_pwm > 0){ //increasing by 2/255 every 250ms is approx 0.4V/s for ramp phase 
 Serial.print("HTR PWM %: ");Serial.println(htr_pwm*20/51);
 analogWrite(pn_htr_out, htr_pwm); //set PWM
 delay(250); htr_pwm -= 2; //increase/ramp
 }
 
 Serial.println(F("-----Sensor Heatup Complete----"));
 return;
}
/* FUNC: L9780 SPI transfer
 * DESC: Fucntion sends a SPI command and receives its result
 * ARGS: d - data being sent on a SPI transfer
 * RETN: spi_buf - data result
 * NOTES: Calls "begin transaction" before every send to ensure
 * that if another SPI library is being used that updates
 * these values, that they're appropriately set for L9780
 */
uint64_t L9780_SPI_xfr(uint64_t d){
 uint64_t spi_buf = d; //data to send
 
 //SPI transfer
 SPI.beginTransaction(SPISettings(L9780_SPI_SPD, L9780_SPI_ORDR, L9780_SPI_MODE)); //start SPI transaction
 digitalWrite(pn_L9780_CS, LOW); // set the CS pin to LOW (on)
 SPI.transfer(&spi_buf,8); //pass address of temp data + size (8 bytes for uint64t)
 digitalWrite(pn_L9780_CS, HIGH); // set the CS pin to HIGH (off)
 SPI.endTransaction(); //end SPI transaction
 
 return spi_buf; //return rx'd data from L9780
}
/* FUNC: L9780 Function - Get status register
 * DESC: Fucntion reads the current status register
 * ARGS: act - true/false to select what is in SO
 * true - RX'd data (current SI)
 * false - status register 
 * RETN: d - SO register
 * NOTES: After sending data, per the datasheet the
 * next SPI frame will have the associated data
 * in the SO depdending on the asserted REG bit.
 */
uint64_t L9780_get_status(bool act){
 if(act = L9780_SO_SI){L9780_SPI_xfr(L9780_rx_reg);}//request input reg back
 else{L9780_SPI_xfr(L9780_status_reg);} //request status reg back
 uint64_t d = L9780_SPI_xfr(L9780_status_reg); //read result
 return d;
}
lang-cpp

AltStyle によって変換されたページ (->オリジナル) /