Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
SPI reading MISO state
29-04-2012, 09:46 PM, (This post was last modified: 30-04-2012, 12:22 AM by KiloOne.)
#1
SPI reading MISO state
Wow, I'm back again already, and again with my MICRO board

During an SPI conversation. I need to pause code execution after I send out a byte until the Pics MISO pin goes HIGH.

I have tried all manner of read syntax and can not seem to prove or disprove that I can read the value of this SPI data line while the SPI is active.

Can anyone tell me if this is possible and what code does this.

In an attempt to create a loop that will work without answering that question, I tried turning off the SPI, reassign pin 37 as input, loop until it goes HIGH and then turn SPI back on.

I can not even get this loop to work, any ideas?

Here is the code that 'should' work:
Code:
    pinMode(39, OUTPUT);            // PIC pin RF0 is pin 39 in digitalw.c
    digitalWrite(39, LOW);            // set CSBI low
    SPI_write(0x10);                // send STCVAD start read all volts conversion and poll status command
    SPI_write(0xB0);                // send PEC of STCVAD command
    
    SPI2CONCLR = 0x8000;            // turn off SPI mode
    Delayus(50);
    pinMode(37, INPUT);
    while (digitalRead (37) == LOW);// MOSI (SDO at LT6803 slave) is RG8 pin 37 in digitaw.c need to loop intil it goes HIGH
    SPI2CONSET = 0x8000;            // turn SPI mode back ON     
    
    pinMode(39, OUTPUT);            // PIC pin RF0 is pin 39 in digitalw.c
    digitalWrite(39, HIGH);            // set CSBI back HIGH
    
    if (getVolts(0x00) == false)
    {

And the SPI lines during this code section:
   

And the code with a 15ms delay to show the state change I want to wait for:
Code:
    pinMode(39, OUTPUT);            // PIC pin RF0 is pin 39 in digitalw.c
    digitalWrite(39, LOW);            // set CSBI low
    SPI_write(0x10);                // send STCVAD start read all volts conversion and poll status command
    SPI_write(0xB0);                // send PEC of STCVAD command
    
    Delayms(15);                    // LT6803should put SDO LOW for about 12ms and then put SDO HIGH
    
    pinMode(39, OUTPUT);            // PIC pin RF0 is pin 39 in digitalw.c
    digitalWrite(39, HIGH);            // set CSBI back HIGH
    
    if (getVolts(0x00) == false)
    {

And the SPI lines during the 15ms delay:
   

Thanks,
Dale
PIC32-Pinguino-OTG Rev C and PIC32-PINGUINO-MICRO rev.B
Win XP SP3
r381 x.3 Big Grin
AND spi.c {} error fixed
AND sdmmc.c pin error fixed
AND diskio.c fixed, MICRO can't use the RTCC
AND analog.c fixed for MICRO
Reply
29-04-2012, 10:02 PM,
#2
RE: SPI reading MOSI state
I'm lost. The PIC's MOSI is driven by the PIC and "just works" doesn't it? Why would you need to look at it or wait for it or anything?

Is your slave doing something weird or what?

John
Reply
30-04-2012, 12:17 AM, (This post was last modified: 30-04-2012, 12:44 AM by KiloOne.)
#3
RE: SPI reading MISO state
John,

Oops , I mean MISO, Post #1 updated. (I really think MISO and MOSI are better than SDI and SDO and there I go being dyslexic).

Yep, weird but I don't see a way around it, but maybe not weird when you rethink as MISO.

They use it to signal completion of ADC conversions and/or give you a flag that the ADC is complete.

The PIC can either wait for the completion by looking at MISO or poll MISO level for completion.

There is even a mode where the completion is signaled by slave generating a 1khz signal on MISO. Not sure how I can code that oneHuh

Dale
PIC32-Pinguino-OTG Rev C and PIC32-PINGUINO-MICRO rev.B
Win XP SP3
r381 x.3 Big Grin
AND spi.c {} error fixed
AND sdmmc.c pin error fixed
AND diskio.c fixed, MICRO can't use the RTCC
AND analog.c fixed for MICRO
Reply
30-04-2012, 12:58 AM, (This post was last modified: 30-04-2012, 12:59 AM by pingotg.)
#4
RE: SPI reading MISO state
Ahhh!

Well I guess you could just keep doing SPI reads (you write anything at all, usually 0) until you see.... I suppose it would be all 1s (so FF).

Sound right?

The device is starting to sound not really SPI.

John
Reply
30-04-2012, 01:15 AM, (This post was last modified: 30-04-2012, 01:30 AM by KiloOne.)
#5
RE: SPI reading MISO state
GREAT IDEA!!

That will get me within 50us or so (back to 250khz just to be safe).

SPI bus looks a little ugly while I'm looping but it works great.

It is this simple:

while (SPI_read() == 0x00); // wait until a read byte is non-zero


Thanks
PIC32-Pinguino-OTG Rev C and PIC32-PINGUINO-MICRO rev.B
Win XP SP3
r381 x.3 Big Grin
AND spi.c {} error fixed
AND sdmmc.c pin error fixed
AND diskio.c fixed, MICRO can't use the RTCC
AND analog.c fixed for MICRO
Reply
30-04-2012, 09:39 AM,
#6
RE: SPI reading MISO state
I like it Smile

I hate busy waits but at some point just go with the flow.

Is it all working now?

I hope you're going to contrinute the working code. I might even have a go at tidying it up if I'm not too busy.

John
Reply
30-04-2012, 10:17 PM, (This post was last modified: 30-04-2012, 10:48 PM by KiloOne.)
#7
RE: SPI reading MISO state
Yes I will post code and would love your tidy suggestions. But.....

I am very close to having it work, however the PIC freezes at random execution points.

I haven't got it to go longer that 6 or 8 seconds before freeze.

No rhyme or reason so far, sometimes freezes in 1 second or so.

Been working all day on trapping this, no luck.

Here is the code that is doing this.

It just sets up I2C and SPI and starts reading the 6803 voltage register every 800ms.

It then displays all 12 voltages on the LCD.

Code:
#include "NHD.c"
#include <delay.c>
#include <spi.c>

u8 cc0[8] = {     // Custom Character 0 v arrow down
    0b00000000,
    0b00000000,
    0b00000000,
    0b00000000,
    0b00010001,
    0b00001010,
    0b00000100,
    0b00000000
};
u8 cc1[8] = {     // Custom Character 1  Delta
      0b00000000,
      0b00000100,
      0b00000000,
      0b00001010,
      0b00000000,
      0b00010101,
      0b00000000,
      0b00000000
};
u8 cc2[8] = {     // Custom Character 2  High decimal
      0b00000000,
      0b00000000,
      0b00000000,
      0b00001100,
      0b00001100,
      0b00000000,
      0b00000000,
      0b00000000
};

char buff[20];                        // for sprintf use
char err[20];                        // for error use
static byte crc8_table[256];          // 8-bit table for PEC calc
static int made_table = 0;            // table made flag
byte addressBYTE;                    // current address byte of the 6803 of interest
byte packet[18];                    // used for PEC calc
byte PECbyte;                        // current PEC as read from SPI bus
byte PECpacket;                        // PEC of packet
byte PECpacketREAD;                    // value that PECpacket should be as read from 6803
static byte addbase = 0b10000000;    // address base
int numbatts;                        // numbatts that are seen (each battery has one LT6803-4)
byte battadd[16];                    // address of seen batts (0-15)
byte scanning;                        // temp
byte CFGR[16][6];                    // Config reg group (possibly communicating with up to 16 LT6803-4 chips)
byte CVR[16][18];                    // Cell Volts reg group
byte FLGR[16][3];                    // Flag reg group
byte TMPR[16][5];                    // Temperature reg group
byte PECreg[16];                    // Packet Error Code register
byte DGNR[16][2];                    // Diagnostic reg group
unsigned long birthV[16];            // ticks at birth of current voltage info in volts array
unsigned long birthT[16];            // ticks at birth of current temperature register info (parsed to tempI, tempB and current)
int volts[16][13];                    // each of up to 16, 6803's, monitors 12 cell voltages
int tempI[16];                        // internal 6803 temperature
int tempB[16];                        // battery surface temperature
int current[16];                    // battery current draw


u8 WaitForMisoHigh() {
    unsigned long startm = millis();
    while (millis() - startm < 300) {        // wait until a read byte is non-zero 300ms is about 20x longer than expected max
        if (SPI_read() != 0) {
            return true;
        }
    }
    sprintf(err, "Wait ERROR");
    show();        
    return false;
}

u8 getVolts()
{
    int i, j, z;
    digitalWrite(39, LOW);                // set CSBI low
    SPI_write(0x1D);                    // send STCVAD ALL BATTERIES  clear voltage registers command
    SPI_write(0x93);                    // send PEC of STCVAD CLEAR command
    
    while (SPI_read() == 0x00); // wait until a read byte is non-zero NO EXIT IF STAYS LOW
    /*
    if (WaitForMisoHigh() == false) {
        return false;    // MISO goes high when command is completed
    }
    */
    
    digitalWrite(39, HIGH);                // set CSBI back HIGH
    
    digitalWrite(39, LOW);                // set CSBI low
    SPI_write(0x10);                    // send STCVAD start read ALL BATTERIES start all cells conversion and poll status command
    SPI_write(0xB0);                    // send PEC of STCVAD command    
    
    while (SPI_read() == 0x00); // wait until a read byte is non-zero NO EXIT IF STAYS LOW
    /*
    if (WaitForMisoHigh() == false) {
        return false;    // MISO goes high when command is completed
    }
    */
    
    digitalWrite(39, HIGH);                // set CSBI back HIGH
    for (i = 1; i <= numbatts; i ++) {
        addressBYTE = addbase | battadd[i];
        setPECbyte(addressBYTE);        // set PECbyte of board address
        digitalWrite(39, LOW);            // set CSBI low
        SPI_write(addressBYTE);         // send board address
        SPI_write(PECbyte);             // send PECbyte of board address
        SPI_write(0x04);                // send read all volts command
        SPI_write(0xDC);                // send PEC of read all volts command
        for (z = 0; z < 18; z ++) {        // get volts reg 1-18    
            packet[z] = SPI_read();
        }
        PECpacketREAD = SPI_read();        // get PEC that data packet should be
        digitalWrite(39, HIGH);            // set CSBI back HIGH
        setPECpacket(18);                // set PECpacket for the 5 bytes in packet[]
        if (PECpacketREAD != PECpacket) {
            if (scanning != true) {
                sprintf(err,  "Bat%u Packet ERROR", battadd[i]);
                show();
            }
        }
        else {
            sprintf(err,  "Bat%u Packet ERROR", battadd[i]);
            clear();
            birthV[battadd[i]] = millis();
            for (z = j = 1; z < 12; z += 2, j += 3) {
                volts[battadd[i]][z] = (int) (((packet[j] & 0xF) << 8) | packet[j - 1]);
                volts[battadd[i]][z + 1] = (int) ((packet[j + 1] << 4) | ((packet[j] & 0xF0) >> 4));
            }
        }
    }
}

void setup() {
    Delayms(200);    
    I2C_init(I2C1, I2C_MASTER_MODE, I2C_100KHZ);
    NHDinit();
    NHDload_custom_character(0, cc0);    // send custom characters to the display V
    NHDload_custom_character(1, cc1);    // send custom characters to the display Delta
    NHDload_custom_character(2, cc2);    // send custom characters to the display High Decimal
    NHDsetBacklight(3);                 // 1-8 1=3ma 2=43ma 3=77ma 4=100ma 5=127ma 6=151ma 7=176ma 8=202ma and 8 hangs up the Micro
    NHDsetContrast(35);                 // 1-50

    SPI_init();                            // left clock at 250khz because at 250khz, reading all 18 volt regs takes 1ms while conversion takes 13ms
    SPI2CONCLR = 0x8000;                // turn off SPI mode before changing an SPI register!!!!!!!!!!!
    SPI2CONCLR = 0x100;                    // clock edge bit(8) to 0                             
    SPI2CONSET = 0x40;                    // clock polarity bit(6) to 1
    SPI2CONSET = 0x200;                    // SMP bit(9) to 1  hex of 2^9
    SPI2CONSET = 0x8000;                // turn SPI mode back ON after changing an SPI register!!!!!!!!!!!
    pinMode(39, OUTPUT);                // #SS CSBI or whatever is PIC pin RF0 at pin 39 in digitalw.c
            
    CFGR[0][0] = 0b00100100;             // CFGR0 configuration register
                        // bits 0-2 UV/OV period 3 bit rep of CDC value '100' is CDC = 4 (500ms)
                        // bit 4 level poll - does not matter until I find way to read state of MISO
                        // bit 5 fets OFF on startup!!!!
    CFGR[0][1] = 0b00000000;             // CFGR1 configuration register
    CFGR[0][2] = 0b00000000;             // CFGR2 configuration register
    CFGR[0][3] = 0b00000000;             // CFGR3 configuration register
    CFGR[0][4] = 0b00000000;             // CFGR4 configuration register
    CFGR[0][5] = 0b00000000;             // CFGR5 configuration register
    writeCFG(0x00);                        // 0x00 writes to all batts!!!!!
    setnumbatts();    
    numbatts = 1;
    battadd[1] = 0;
}

void loop() {
    int vvv, i, z;
    getVolts();    
    z = 0;    
    if (millis() - birthV[z] <= 200) {
        for (i = 1; i < 13; i =  i + 4) {        // print current batt volts for battery z to LCD (no decimal yet)
            NHDsetCursor((i-1)/4, 0);
            vvv = (((((int) volts[z][i] - 512)*3)/2)+2)/10;
            sprintf(buff, "%5i", vvv);    //+2 is fudge, down from +5 to match DVM readings
            NHDprintf(buff);
            vvv =  (((((int) volts[z][i+1] - 512)*3)/2)+2)/10;
            sprintf(buff, "%5i", vvv);
            NHDprintf(buff);
            vvv = (((((int) volts[z][i+2] - 512)*3)/2)+2)/10;
            sprintf(buff, "%5i", vvv);
            NHDprintf(buff);
            vvv =  (((((int) volts[z][i+3] - 512)*3)/2)+2)/10;
            sprintf(buff, "%5i", vvv);
            NHDprintf(buff);
        }
        NHDsetCursor(3,6);
        sprintf(buff, "%6lu, %6lu", millis() - birthV[z], birthV[z]);    //print to LCD ms from when we captured volts and current ms from startup
        NHDprintf(buff);
    }
    else {
        NHDclear();
        sprintf(buff, "Reset %6lu", millis());
        NHDprintf(buff);
    }
    Delayms(800);
}

void show() {
    NHDsetCursor(2, 0);        // line 2 will be reserved for errors eventually
    NHDprintf(err);            // need to add err's to an array so that mutiple error can be active and scrolled
}

void clear() {
    NHDsetCursor(2, 0);        // need to look for err in error array and remove it
    NHDprintf("                    ");
}

void writeCFG(byte ibb) {
    int i;                    
    addressBYTE = addbase | ibb;
    setPECbyte(addressBYTE);        // set PECbyte of board address
    for (i = 0; i < 6; i ++) {
        packet[i] = CFGR[ibb][i];
    }
    setPECpacket(6);
    digitalWrite(39, LOW);            // set CSBI low
    if (ibb != 0x00) {
        SPI_write(addressBYTE);     // send board address
        SPI_write(PECbyte);         // send PECbyte of board address
    }
    SPI_write(0x01);                // send write config reg WRCFG command
    SPI_write(0xC7);                // send PEC of WRCFG command
    for (i = 0; i < 6; i ++) {
        SPI_write(CFGR[ibb][i]);
    }
    SPI_write(PECpacket);
    digitalWrite(39, HIGH);            // set CSBI back HIGH
}

static void init_crc8() {
    int z,j;
    byte cr;
    if (!made_table) {
        for (z = 0; z < 256; z ++) {
            cr = z;
            for (j = 0; j < 8; j ++) {
                cr = (cr << 1) ^ ((cr & 0x80) ? 0x07 : 0);
            }
            crc8_table[z] = cr & 0xFF;
        }
        made_table = 1;
    }
}

void setPECbyte(byte m) {
    PECbyte = 0x41;                            // initialize PECbyte
    if (!made_table) {
        init_crc8();
    }
    PECbyte = crc8_table[(PECbyte) ^ m];
}

void setPECpacket(byte np) {                // np is number of bytes currently in packet[]
    int z;
    PECpacket = 0x41;                        // initialize PECpacket
    if (!made_table) {
        init_crc8();
    }
    for (z = 0; z < np; z ++) {
        PECpacket = crc8_table[(PECpacket) ^ packet[z]];
    }
}

void setnumbatts() {
    int i;
    numbatts = 0;
    for (i =  0; i < 16; i ++) {
        numbatts = numbatts + 1;
        battadd[numbatts] = i;
    }
    scanning = true;
    getVolts();
    scanning = false;
    numbatts = 0;
    for (i =  0; i < 16; i ++) {
        if (birthV[i] == 0) {
        }
        else {
            numbatts = numbatts + 1;
            battadd[numbatts] = i;
        }
    }    
    NHDsetCursor(0, 0);
    NHDprintf("numbatts ");
    sprintf(buff, "%3X", numbatts);
    NHDprintf(buff);
    sprintf(buff, "%3X", battadd[1]);
    NHDprintf(buff);
    Delayms(1000);
    NHDclear();
}

And here is a view of the I2C bus where you can see it freezes in the middle of reading an ACK from the display. This is not where it will freeze the next time.
   

Any experience on freezing problems like this?

Thanks,
Dale
PIC32-Pinguino-OTG Rev C and PIC32-PINGUINO-MICRO rev.B
Win XP SP3
r381 x.3 Big Grin
AND spi.c {} error fixed
AND sdmmc.c pin error fixed
AND diskio.c fixed, MICRO can't use the RTCC
AND analog.c fixed for MICRO
Reply
01-05-2012, 12:43 AM,
#8
RE: SPI reading MISO state
I dread such things, not least because I don't have any such handy test equipment!

If you've checked all the grounds are well connected and agonised about voltage levels and noise, then, er, don't know!!

John
Reply
01-05-2012, 09:12 AM,
#9
RE: SPI reading MISO state
Dale,

from my experience I2C has the inherent risk of freezing, i NEVER use it for that reason and do all by SPI .
Possibly the origin of your problem is to be found in interference from interrupts but it is likely you do not want to disable interrupts for each I2C communication. However to get confirmed this is happening you could perhaps try that.

regards jpc
Reply
01-05-2012, 04:05 PM, (This post was last modified: 01-05-2012, 07:18 PM by KiloOne.)
#10
RE: SPI reading MISO state
Hi jpc,

GREAT lead you gave me!!!

I have found that disabling interrupts solved the problem.

However with your input I am tempted to switch the 4x20 NHD display over to SPI but that would involve adding a wire for CS and potential conflicts with my 'less than standard' LT6803 SPI devices. So, I will persevere with I2C for now.

I used core routines from interrupt.c to confirm that interrupts were causing my problem.

I added calls to them in my NHD.c code. I disabled all interrupts before any I2C_start call and enabled them again after I2C_stop calls. No more freezing - yeah.Smile

Now I want to see what IRQ's are causing the problem.

Soooo, I needed to start turning off IRQ's selectively to isolate the cuplprit/s.

To do this I added a function in interrupt.c that I thought returned the current enabled interrupts status into an unsigned int variable (orgINTs):

Code:
/* dk needed status
*/
unsigned int IntGetStatus()
{
    unsigned int intStatus;
    intStatus = _CP0_GET_STATUS(); // Get Status
    return intStatus;
}

Then in NHD.c:
1. Set orgINTs with IntGetStatus
2. I then disabled all 58 interrupts (0-57) individually in a loop containing IntDisable(i)
3. I then did my I2C suff.
4. I then re-enabled ints with IntRestoreInterrupts(orgINTs).

With result: didn't freeze but still had issues

Why is the above not the same as this ???????????????????? :
1. orgINTs = IntDisableInterrupts()
2. do my I2C stuff
3. IntRestoreInterrupts(orgINTs)

With result: everything works!!!

And, how do they save the interrupt enabled status of 58 interrupts in just a 16 bit unsigned int????

It may just be that since I have no plans to use any interrupts, I will not try to further isolate the problem and use it with all interrupts disabled.

What problems could I expect to encounter if I just did this?

Dale
PIC32-Pinguino-OTG Rev C and PIC32-PINGUINO-MICRO rev.B
Win XP SP3
r381 x.3 Big Grin
AND spi.c {} error fixed
AND sdmmc.c pin error fixed
AND diskio.c fixed, MICRO can't use the RTCC
AND analog.c fixed for MICRO
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)