MODSERIAL and SDFileSystem Don't Like Each Other

07 Mar 2011

So I got a CH robotics UM6 IMU/AHRS and just got the mbed to read all the data over the uart with MODSERIAL. I've been trying to log this data using SDFileSystem and my coolcomponents board. I can write to the card when using the SDFileSystem hello world. I know that your not supposed to use printf() with MODSERIAL. I got the program to print one value out of the 50 different ways i've tried it. Most of the time the program doesn't want to run even with just the SDFileSystem.h and the SDFileSystem sd(p5, p6, p7, p8, "sd") defined.

Assuming I can get it to run (consistently) with just the includes for SDFileSystem, is there a way to disable the MODSERIAL attach interrupt so I can write to the SD card?

I'll post the code if anyone is interested, but for now I'm not including it because its really long and not separated into functions and headers.

07 Mar 2011

You need to post the code. If you need to stop the serial IRQs it's pretty simple. However, I would be surprised if that's the problem so lets see your code to see if we can figure out what the problem is.

07 Mar 2011

Just found this in MODSERIAL, I'll give it a try for writing to the SD card.

 /**
     * Disable the interrupts for this Uart.
     * @ingroup INTERNALS
     */
    void disableIrq(void);
    
    /**
     * Enable the interrupts for this Uart.
     * @ingroup INTERNALS
     */
    void enableIrq(void);
07 Mar 2011

They are protected methods used interally so you can't call them from your program. Can you publish your program and provide a link to it. I have some Mbeds in CoolComp boards so can simulate ur setup. But you need to publish your code :)

07 Mar 2011

Alright here's the main. It's really messy and most of it I used from the UM6 firmware source. I should really take out alot of the stuff left over from the UM6 firmware that was used for its buffering.

(It does nothing as it is, no led's, nothing) If I take all the SD card stuff out it works (gets data from IMU)

#include "mbed.h"          // MBED LIBRARY
#include "MODSERIAL.h"     // MBED BUFFERED SERIAL
#include "SDFileSystem.h"  // MBED SD LIBRARY


#include "UM6_usart.h"     // UM6 USART HEADER
#include "UM6_config.h"    // UM6 CONFIG HEADER

 // ADDED: Counter for SD data logging
 static uint8_t got_data_counter = 0;
    
//int16_t MY_DATA_GYRO_PROC_X;
int16_t MY_DATA_EULER_PSI;

// SETUP (ASSIGN) SERIAL COMMUNICATION PINS ON MBED
MODSERIAL pc(USBTX, USBRX);  // PC SERIAL OVER USB PORT ON MBED
MODSERIAL uart(p28, p27);    // UM6 SERIAL OVER UART PINS 28 & 27
//MODSERIAL uart(p13, p14);

// SETUP (ASSIGN) SPI COMMUNICATION PINS ON MBED FOR SD CARD ON COOLCOMPONENTS WORKSHOP BOARD
SDFileSystem sd(p5, p6, p7, p8, "sd"); // the pinout on the mbed Cool Components workshop board

// SETUP (ASSIGN) MBED LED (1 thru 3) FOR VISUAL DEBUGGING ON MBED 
DigitalOut pc_activity(LED1);    // LED1 = PC SERIAL
DigitalOut uart_activity(LED2);  // LED2 = UM6 SERIAL
DigitalOut sd_activity(LED3);    // LED3 = SD CARD 


// FROM UM6 FIRMWARE SOURCE
// USART RX buffer and associated index and flags
volatile char gRXBuf[RX_BUF_SIZE];
volatile int32_t gRXBufPtr = 0;
volatile char gRXPacketReceived = 0;
volatile char gRXBufOverrun = 0;

// Queue for packets received by the USART.  This is a FIFO circular buffer.
volatile USARTPacket gRXPacketBuffer[RX_PACKET_BUFFER_SIZE];
volatile uint8_t gRXPacketBufferStart = 0;
volatile uint8_t gRXPacketBufferEnd = 0;

// Flag for storing the current USART state
uint8_t gUSART_State = USART_STATE_WAIT;

/*******************************************************************************
* Function Name  : ComputeChecksum
* Input          : USARTPacket* new_packet
* Output         : None
* Return         : uint16_t
* Description    : Returns the two byte sum of all the individual bytes in the
                         given packet.
*******************************************************************************/
uint16_t ComputeChecksum( USARTPacket* new_packet ) {
    int32_t index;
    uint16_t checksum = 0x73 + 0x6E + 0x70 + new_packet->PT + new_packet->address;

    for ( index = 0; index < new_packet->data_length; index++ ) {
        checksum += new_packet->packet_data[index];
    }
    return checksum;
}







// MBED MODSERIAL INTERUPT FUNCTION
// This function is called when a character goes into the RX buffer.
void rxCallback(void) {
    uart_activity = !uart_activity;  // Lights LED when uart interupt 
    
    
    while(uart.rxBufferGetCount() >  MAX_PACKET_DATA) {
    
    // UM6 Firmware Source Function ProcessNextCharacter()
//void ProcessNextCharacter( ) {
    static uint8_t data_counter = 0;
    
   
    
    static USARTPacket new_packet;

    // The next action should depend on the USART state.
    switch ( gUSART_State ) {
            // USART in the WAIT state.  In this state, the USART is waiting to see the sequence of bytes
            // that signals a new incoming packet.
        case USART_STATE_WAIT:
            if ( data_counter == 0 ) {     // Waiting on 's' character
                if ( uart.getc() == 's' ) {
                   
                    data_counter++;
                } else {
                    data_counter = 0;
                }
            } else if ( data_counter == 1 ) {    // Waiting on 'n' character
                if ( uart.getc() == 'n' ) {
                    data_counter++;

                } else {
                    data_counter = 0;
                }
            } else if ( data_counter == 2 ) {    // Waiting on 'p' character
                if ( uart.getc() == 'p' ) {
                    // The full 'snp' sequence was received.  Reset data_counter (it will be used again
                    // later) and transition to the next state.
                    data_counter = 0;
                    gUSART_State = USART_STATE_TYPE;               

                } else {
                    data_counter = 0;
                }
            }
            break;

            // USART in the TYPE state.  In this state, the USART has just received the sequence of bytes that
            // indicates a new packet is about to arrive.  Now, the USART expects to see the packet type.
        case USART_STATE_TYPE:

            new_packet.PT = uart.getc();

            gUSART_State = USART_STATE_ADDRESS;

            break;

            // USART in the ADDRESS state.  In this state, the USART expects to receive a single byte indicating
            // the address that the packet applies to
        case USART_STATE_ADDRESS:
            new_packet.address = uart.getc();
            //  pc.putc(new_packet.address);

            // For convenience, identify the type of packet this is and copy to the packet structure
            // (this will be used by the packet handler later)
            if ( (new_packet.address >= CONFIG_REG_START_ADDRESS) && (new_packet.address < DATA_REG_START_ADDRESS) ) {
                new_packet.address_type = ADDRESS_TYPE_CONFIG;
            } else if ( (new_packet.address >= DATA_REG_START_ADDRESS) && (new_packet.address < COMMAND_START_ADDRESS) ) {
                new_packet.address_type = ADDRESS_TYPE_DATA;
            } else {
                new_packet.address_type = ADDRESS_TYPE_COMMAND;
            }

            // Identify the type of communication this is (whether reading or writing to a data or configuration register, or sending a command)
            // If this is a read operation, jump directly to the USART_STATE_CHECKSUM state - there is no more data in the packet
            if ( (new_packet.PT & PACKET_HAS_DATA) == 0 ) {
                gUSART_State = USART_STATE_CHECKSUM;


                // IF READ OP
                // pc.putc('C');
                // pc.putc('K');
                // pc.putc('S');

            }
            // If this is a write operation, go to the USART_STATE_DATA state to read in the relevant data
            else {
                gUSART_State = USART_STATE_DATA;
                // Determine the expected number of bytes in this data packet based on the packet type.  A write operation
                // consists of 4 bytes unless it is a batch operation, in which case the number of bytes equals 4*batch_size,
                // where the batch size is also given in the packet type byte.
                if ( new_packet.PT & PACKET_IS_BATCH ) {
                    new_packet.data_length = 4*((new_packet.PT >> 2) & PACKET_BATCH_LENGTH_MASK);

                  //  pc.putc(new_packet.data_length);
                     //  pc.putc('B');
                     //  pc.putc('A');
                     //  pc.putc('T');
                     //  pc.putc('C');
                     //  pc.putc('H');

                } else {
                    new_packet.data_length = 4;
                }
            }
            break;

            // USART in the DATA state.  In this state, the USART expects to receive new_packet.length bytes of
            // data.
        case USART_STATE_DATA:
            new_packet.packet_data[data_counter] =  uart.getc();

            //  pc.putc('D');
            //  pc.putc('A');
            //  pc.putc('T');
            //  pc.putc('A');

            data_counter++;

            // If the expected number of bytes has been received, transition to the CHECKSUM state.
            if ( data_counter == new_packet.data_length ) {
                // Reset data_counter, since it will be used in the CHECKSUM state.
                data_counter = 0;
                gUSART_State = USART_STATE_CHECKSUM;
            }
            break;



            // USART in CHECKSUM state.  In this state, the entire packet has been received, with the exception
            // of the 16-bit checksum.
        case USART_STATE_CHECKSUM:
            // Get the highest-order byte
            if ( data_counter == 0 ) {
                // uint8_t Temp_Packet = uart.getc();
                new_packet.checksum = ((uint16_t)uart.getc() << 8);
                data_counter++;
            } else { // ( data_counter == 1 )
                // Get lower-order byte
                new_packet.checksum = new_packet.checksum | ((uint16_t)uart.getc() & 0x0FF);

                // Both checksum bytes have been received.  Make sure that the checksum is valid.
                uint16_t checksum = ComputeChecksum( &new_packet );



                // If checksum does not match, send a BAD_CHECKSUM packet
                if ( checksum != new_packet.checksum ) {
                    // Send bad checksum packet
                    // new_packet.PT = PACKET_NO_DATA;
                    // new_packet.address = UM6_BAD_CHECKSUM;
                    // new_packet.data_length = 0;    // No data bytes
                    // new_packet.checksum = ComputeChecksum( &new_packet );
                    // SendTXPacketSafe( &new_packet );

                }

                else

                {

                    //  Packet was received correctly.  Add the packet to the RX packet buffer and
                    //  set a flag indicating that a new packet has been received.
                    //  AddRXPacket( &new_packet );
                    gRXPacketReceived = 1;
               
               
               
               
               //-----------------------------------------------------------------------------------------------
               //-----------------------------------------------------------------------------------------------
               //
               // ADDED: CHECKSUM WAS GOOD SO GET ARE DATA!!!!!!!!!!!!


                // IF DATA ADDRESS
                if  (new_packet.address_type == ADDRESS_TYPE_DATA) {
                    // pc.putc(ADDRESS_TYPE_DATA);

                    // FIGURE OUT WHAT DATA IT IS
                    // pc.putc(new_packet.address);

                  

                    //------------------------------------------------------------
                    // UM6_GYRO_PROC_XY (0x5C)
                    // To convert the register data from 16-bit 2's complement integers to actual angular rates in degrees
                    // per second, the data should be multiplied by the scale factor 0.0610352 as shown below
                    // angular_rate = register_data*0.0610352

                    if (new_packet.address == UM6_GYRO_PROC_XY) {

                        // GYRO_PROC_X
                        int16_t MY_DATA_GYRO_PROC_X = (int16_t)new_packet.packet_data[0]<<8; //bitshift it
                        MY_DATA_GYRO_PROC_X |= new_packet.packet_data[1];
                       // pc.printf( "GPx %f deg/s\n",MY_DATA_GYRO_PROC_X*0.0610352);

                      
                        int16_t MY_DATA_GYRO_PROC_Y = (int16_t)new_packet.packet_data[2]<<8; //bitshift it
                        MY_DATA_GYRO_PROC_Y |= new_packet.packet_data[3];
                       // pc.printf( "GPy %f d/s\n",MY_DATA_GYRO_PROC_Y*0.0610352);
                    
                    //------------------------------------------------------------


                    //------------------------------------------------------------
                    // UM6_GYRO_PROC_Z (0x5D)
                    // To convert the register data from a 16-bit 2's complement integer to the actual angular rate in
                    // degrees per second, the data should be multiplied by the scale factor 0.0610352 as shown below.


                        // GYRO_PROC_Z
                          int16_t MY_DATA_GYRO_PROC_Z = (int16_t)new_packet.packet_data[4]<<8; //bitshift it
                          MY_DATA_GYRO_PROC_Z |= new_packet.packet_data[5];
                          //pc.printf( "GPz %f deg/s\n",MY_DATA_GYRO_PROC_Z*0.0610352);
                    }
                    //------------------------------------------------------------


                    //------------------------------------------------------------
                    // UM6_ACCEL_PROC_XY (0x5E)
                    // To convert the register data from 16-bit 2's complement integers to actual acceleration in gravities, 
                    // the data should be multiplied by the scale factor 0.000183105 as shown below. 
                    // acceleration = register_data* 0.000183105
                    if (new_packet.address == UM6_ACCEL_PROC_XY) {

                        // ACCEL_PROC_X
                          int16_t MY_DATA_ACCEL_PROC_X = (int16_t)new_packet.packet_data[0]<<8; //bitshift it
                          MY_DATA_ACCEL_PROC_X |= new_packet.packet_data[1];
                         // pc.printf( "Apx %f g \n",MY_DATA_ACCEL_PROC_X*0.000183105);
                         
                       // ACCEL_PROC_Y
                          int16_t MY_DATA_ACCEL_PROC_Y = (int16_t)new_packet.packet_data[2]<<8; //bitshift it
                          MY_DATA_ACCEL_PROC_Y |= new_packet.packet_data[3];
                         // pc.printf( "Apy %f g \n",MY_DATA_ACCEL_PROC_Y*0.000183105);   
                         
                    //------------------------------------------------------------
                
                    
                    //------------------------------------------------------------
                    // UM6_ACCEL_PROC_Z (0x5F) 
                    // To convert the register data from a 16-bit 2's complement integer to the actual acceleration in 
                    // gravities, the data should be multiplied by the scale factor 0.000183105 as shown below.  
              
                        // ACCEL_PROC_Z
                          int16_t MY_DATA_ACCEL_PROC_Z = (int16_t)new_packet.packet_data[4]<<8; //bitshift it
                          MY_DATA_ACCEL_PROC_Z |= new_packet.packet_data[5];
                         // pc.printf( "Apz %f g \n",MY_DATA_ACCEL_PROC_Z*0.000183105);                  
                    } 
   
                    //------------------------------------------------------------
                      
                      
                    //------------------------------------------------------------      
                    // UM6_MAG_PROC_XY (0x60)
                    // To convert the register data from 16-bit 2's complement integers to a unit-norm (assuming proper 
                    // calibration)  magnetic-field vector, the data should be multiplied by the scale factor 0.000305176 as 
                    // shown below.
                    // magnetic field = register_data* 0.000305176 
                    if (new_packet.address == UM6_MAG_PROC_XY) {

                        // MAG_PROC_X
                          int16_t MY_DATA_MAG_PROC_X = (int16_t)new_packet.packet_data[0]<<8; //bitshift it
                          MY_DATA_MAG_PROC_X |= new_packet.packet_data[1];
                       //   pc.printf( "Mpx %f \n",MY_DATA_MAG_PROC_X*0.000305176);
                         
                       // MAG_PROC_Y
                          int16_t MY_DATA_MAG_PROC_Y = (int16_t)new_packet.packet_data[2]<<8; //bitshift it
                          MY_DATA_MAG_PROC_Y |= new_packet.packet_data[3];
                       //   pc.printf( "Mpy %f \n",MY_DATA_MAG_PROC_Y*0.000305176); 

                    //------------------------------------------------------------ 


                    //------------------------------------------------------------
                    // UM6_MAG_PROC_Z (0x61) 
                    // To convert the register data from 16-bit 2's complement integers to a unit-norm (assuming proper 
                    // calibration)  magnetic-field vector, the data should be multiplied by the scale factor 0.000305176 as 
                    // shown below. 
                    // magnetic field = register_data*0.000305176

                        // MAG_PROC_Z
                          int16_t MY_DATA_MAG_PROC_Z = (int16_t)new_packet.packet_data[4]<<8; //bitshift it
                          MY_DATA_MAG_PROC_Z |= new_packet.packet_data[5];
                       //   pc.printf( "Mpz %f \n",MY_DATA_MAG_PROC_Z*0.000305176);
                   
                    }
                    //------------------------------------------------------------


            
                    //------------------------------------------------------------
                    // UM6_EULER_PHI_THETA (0x62) 
                    // Stores the most recently computed roll (phi) and pitch (theta) angle estimates.  The angle 
                    // estimates are stored as 16-bit 2's complement integers.  To obtain the actual angle estimate in 
                    // degrees, the register data should be multiplied by the scale factor 0.0109863 as shown below
                    // angle estimate = register_data* 0.0109863
                    if (new_packet.address == UM6_EULER_PHI_THETA) {
                     // EULER_PHI (ROLL)
                          int16_t MY_DATA_EULER_PHI = (int16_t)new_packet.packet_data[0]<<8; //bitshift it
                          MY_DATA_EULER_PHI |= new_packet.packet_data[1];
                         // pc.printf( "PHI %f deg \n",MY_DATA_EULER_PHI*0.0109863);
                         
                       
                     // EULER_THETA (PITCH)
                          int16_t MY_DATA_EULER_THETA = (int16_t)new_packet.packet_data[2]<<8; //bitshift it
                          MY_DATA_EULER_THETA |= new_packet.packet_data[3];
                       //   pc.printf( "THETA %f deg \n",MY_DATA_EULER_THETA*0.0109863);  
                    
                    //------------------------------------------------------------
                    
                    
                    
                  
                    //------------------------------------------------------------
                    // UM6_EULER_PSI (0x63) (YAW)
                    // Stores the most recently computed yaw (psi) angle estimate.  The angle estimate is stored as a 16-
                    // bit 2's complement integer.  To obtain the actual angle estimate in degrees, the register data 
                    // should be multiplied by the scale factor 0.0109863 as shown below
                  //  if (new_packet.address == UM6_EULER_PSI) {
                           // int16_t 
                            MY_DATA_EULER_PSI = (int16_t)new_packet.packet_data[4]<<8; //bitshift it
                            MY_DATA_EULER_PSI |= new_packet.packet_data[5];
                          //  pc.printf( "PSI %f deg \n",MY_DATA_EULER_PSI*0.0109863);

                    }
                    //------------------------------------------------------------
               
               
                }  

                // A full packet has been received.
                // Put the USART back into the WAIT state and reset
                // the data_counter variable so that it can be used to receive the next packet.
                data_counter = 0;
                gUSART_State = USART_STATE_WAIT;
                
                // ADDED: This is a counter for the SD data logging
                   got_data_counter ++;
              
                }
            }
            break;

    }
}
}

int main() {
    // SD DATA LOGGING
    // mkdir("/sd/", 0777);
   //  sd_activity = !sd_activity;

    // set serial uart baud 115200
    uart.baud(115200);

    // set pc baud 115200
    pc.baud(115200);
   
    // attach interupt function to uart
    uart.attach(&rxCallback, MODSERIAL::RxIrq);

       if ( got_data_counter == 50 ) {
                    FILE *fp = fopen("/sd/UM6_DATA.txt", "w");
                    if(fp == NULL) {
                    error("Could not open file for write\n");
                    }
     
                   // fprintf(fp, "GYRO_PROC_X = %f deg/s \n",MY_DATA_GYRO_PROC_X);    
                    fprintf(fp, "EULER PSI (YAW) = %f deg \n", MY_DATA_EULER_PSI);
                    fclose(fp); 
                    
                    sd_activity = !sd_activity;
                    
                    got_data_counter = 0;  // Reset Data Counter
                    }

}
07 Mar 2011

The source code and datasheet for the IMU is at: http://www.chrobotics.com/index.php?main_page=product_info&products_id=5

It runs a ST103f, I think off the top of my head, cortex-M3

07 Mar 2011

Never published code before, will try right now, I think I left all the author info from ch robotics in it so that should be alright.

07 Mar 2011
07 Mar 2011

Just looking now. But I can see why you are having problems. You've used RxIrq the IRQ callback incorrectly. Modserial buffers for you. So you should NEVER be waiting around inside for the IRQ callback for another character. I'll make a up a program that shows you what you should be doing. I'll post shortly.

07 Mar 2011

If I understand correctly (I probably don't) with MODSERIAL when you use getc() it just reads a character out of the buffer right. I put the while loop in the beginning of the interrupt function to only process all the data if theres more than the max byte length for the UM6 of 40 bytes in the buffer.

What I think I need is a way to only call the interrupt when there is more than 40 bytes in the buffer.

07 Mar 2011

The problem is that you are trying to use getc() (and other functions like rxBufferGetCount()) INSIDE rxCallback. That's not how you do it at all. I'll publish a simple demo that shows the correct usage shortly.

07 Mar 2011

I get what your saying. The interrupt just handles the buffering and I make my own function OUTSIDE of the interrupt to process the data thats in the buffer. I can't believe that what I was doing actually worked at a 115200 baud and a rate of 200 Hz.

Thanks, I'm really impressed with the mbed and extremely impressed with your quick answer at 2am here in California that kept me from going further down the completely wrong path.

This is for my undergraduate mechanical engineering autonomous parafoil project and I got in a mexican standoff with another group member because I choose the mbed and he thinks arduino can do anything. There's no way that what I just put the mbed through would still be functional on an arduino.

07 Mar 2011

Having looked at what you are trying to do and the UM6 datasheet I would have approached this by creating a "UM6 class library" that handles the device in an abstract way. However, I can see you are "just needing to get going". So, moving on, first up, there's really no need to use MODSERIAL when you are just handling a stream of bytes in this way. You could use it to buffer the stream if you find you are dropping some chars because you are not handling the packet fast enough. But at the end of the day that will only handle a burst sequence whereby you "get some time later" to process them. But, that said, you still need to handle them one way or another.

So, here's a "snippet" to get you going (note, a snippet isn't a program, I haven't compiled this, it's merely to show you how to go about demuxing the stream of data from the UM6 using a simple state machine)

#include "mbed.h"          // MBED LIBRARY

Serial uart(p28, p27);     // UM6 SERIAL OVER UART PINS 28 & 27

USARTPacket new_packet;

#define UM6_WAITING_FOR_s   0
#define UM6_WAITING_FOR_n   1
#define UM6_WAITING_FOR_p   2
#define UM6_WAITING_FOR_PT  3
#define UM6_GETTING_ADDRESS 5
#define UM6_GETTING_PACKET  6
#define UM6_GETTING_CSUM1   7
#define UM6_GETTING_CSUM0   8
int UM6_state;

int UM6_packet_index;

volatile bool have_packet;

void rxCallback(void) {
    uint8_t c = (uint8_t)uart.getc();
    if (have_packet == true) {
        // Oh dear, we haven't processed the last packet that we
        // got so we have to drop chars until we do have. The other
        // way would be to implement USARTPacket buffers. But at 
        // some point you have to handle the incoming data faster
        // they arrive. In which case you may need to lower uart
        // baud rate for example.
        return;
    }
    switch (UM6_state) {
        case UM6_WAITING_FOR_s:
            if (c == 's') UM6_state = UM6_WAITING_FOR_n; break;
        case UM6_WAITING_FOR_n:
            if (c == 'n') UM6_state = UM6_WAITING_FOR_p; 
            else UM6_state = UM6_WAITING_FOR_s; 
            break;
        case UM6_WAITING_FOR_p:
            if (c == 'p') UM6_state = UM6_WAITING_FOR_PT; 
            else UM6_state = UM6_WAITING_FOR_s; 
            break;
        case UM6_WAITING_FOR_PT:
            new_packet.PT = c;
            new_packet.data_length = (c >> 2) & 0xF;
            UM6_state = UM6_GETTING_ADDRESS;
            break;
        case UM6_GETTING_ADDRESS:     
            new_packet.address = c;
            UM6_packet_index = 0;
            UM6_state = UM6_GETTING_PACKET;
            break;
        case UM6_GETTING_PACKET:
            new_packet.packet_data[UM6_packet_index++] = c;
            if (UM6_packet_index == new_packet.data_length) {
                UM6_state = UM6_GETTING_CSUM1;
            }
            break;
        case UM6_GETTING_CSUM1:
            new_packet.checksum = (c << 8) & 0xFF00;
            UM6_state = UM6_GETTING_CSUM0;
            break;
        case UM6_GETTING_CSUM0:
            new_packet.checksum |= (c & 0xFF);
            UM6_state = UM6_WAITING_FOR_s;
            have_packet = true;
            break;
    }
}

void processPacket(void) {
    // This is where you put your code that
    // processes the contents of the USARTPacket new_packet
}

int main() {    
    uart.baud(115200);

    // Setup the receiver state machine to seek the start byte sequence.
    UM6_state = UM6_WAITING_FOR_s;
    
    // Flag no packet yet available.
    have_packet = false;
    
    // We are ready to start receiving bytes.
    uart.attach(&rxCallback, Serial::RxIrq);

    while(1) {
        if (have_packet == true) {
            // global var new_packet has now been filled with data
            // from the uart serial port. You should now be calling 
            // a function the processes the new_packet data you have
            // received.            
            processPacket();
            
            // Flag done with this packet.
            have_packet = false;
        }        
    }
}
07 Mar 2011

Alright I think I have followed some of your recommendations. I'm still using MODSERIAL because the max complete packet size sent by the UM6 is 40. My current setting on the UM6 send out 15 bytes for each total packet, this loops through for the gyro, accell, mag, and estimated Euler angles. I don't want my program ever to just wait around for the UM6 packets so I'm still using MODSERIAL to buffer because I think the hardware UART FIFO on the mbed is only 16 bytes.

Here's some snippets of my method of attack.

I've gotten rid of the attach interrupt function completely. In main I do: (MAX_PACKET_DATA = 40)

while(1) {
  if(uart.rxBufferGetCount() >  MAX_PACKET_DATA) {
        ProcessPacket();
     }
}

This works and I can get all the data, but once again if I try to include the SDFileSystem

#include "SDFileSystem.h"  // MBED SD LIBRARY

and setup the spi/sd card for the coolcomponents board:

SDFileSystem sd(p5, p6, p7, p8, "sd"); // the pinout on the mbed Cool Components workshop board

The program doesn't work anymore. I'm not using any of the SD stuff, I'm just including the header and initializing the spi pins.

07 Mar 2011

Here's a screenshot from using printf() to output the Euler angles to the pc. Note when I tested the SD stuff I disabled the printf() outputs. /media/uploads/lhiggs/moserial.png

08 Mar 2011

What size buffers are you using for MODSERIAL? I know that SDFileSystem init start up time can take some time, it's not the quickest thing in the world.

Also, try adding this:-

void rxOvflow(void) {
    error("Ouch, overflowed");
}

// In main after setting the uart baud rate and before attaching your rxCallback function add:-

    uart.attach(&rxOvflow, MODSERIAL::RxOvIrq);

The above code would halt your Mbed and flash the LEDs with the blue lights of death signalling an RX buffer overflow. I suspect that at 115200 baud the delay in init the SD card maybe causing problems somewhere.

You could also try init the SD system after setting up the serial system. To do this you'd need something like this:-

SDFileSystem *sd;

int main() {

    // Setup the uart serial port, then...

    sd = new SDFileSystem(p5, p6, p7, p8, "sd");

}

By doing this you delay the init port of the file system. I would also design the serial to drop packets until after sd is setup.

And one last thing. You are using 115200 which is pretty quick. In circulstances like this I would drop to 9600 and see it it functionally works (albeit slower than you want). Then, if 9600 works go to 19200, etc etc. Ramping up until it breaks. Then you have a good clue what's going on.

08 Mar 2011

Ok I'll try all your suggestions. I've been working on a very simple test program called MODSERIAL_vs_SDFileSystem

It doesn't work as it is, but I think I got some real issues with the mbed flash loader. Even with simple programs like this one (but functional) I'll compile and it will blink the usb led then when I hit the reset button it won't work. Sometimes I will just hit compile again and wait for the usb led to stop blinking, hit reset and then it will work. I've gotten into the habit of moving all the mbed programs to the trash, emptying the trash, and reseting moserial terminal, every time I compile a program. It's really driving me mad because I don't know if the changes I make to a program make the program not functional, or if its the boot loader acting up again.

I have noticed, that even brand new if you compile a program and it saves a another copy of the same name program(2) that many times it won't load this new program into the flash, even though the flash is supposed to get the newest program on the drive.

Maybe it has something to do with using the mbeds on both Ubuntu Linux and MS Vista. I usually do most on Ubuntu because I really like moserial and the recommended serial terminal for MS that I have tried have crashed Windows many times. Anyways I noticed yesterday that when in Vista it was acting like it didn't have the mbed drivers anymore and it just got stuck on the searching for "microcontroller driver" page. Maybe this has something to do with it.

Anyways heres my test program, if you could try it on a coolcomponents board and let me know if you have problems or it's just my mbed bootloader. Thanks

#include "mbed.h"
#include "MODSERIAL.h"     // MBED BUFFERED SERIAL
#include "SDFileSystem.h"  // MBED SD LIBRARY

DigitalOut myled(LED1);
DigitalOut sd_activity(LED3);

// SETUP (ASSIGN) SERIAL COMMUNICATION PINS ON MBED
MODSERIAL pc(USBTX, USBRX);  // PC SERIAL OVER USB PORT ON MBED
MODSERIAL uart(p28, p27);    // UM6 SERIAL OVER UART PINS 28 & 27

// SETUP (ASSIGN) SPI COMMUNICATION PINS ON MBED FOR SD CARD ON COOLCOMPONENTS WORKSHOP BOARD
SDFileSystem sd(p5, p6, p7, p8, "sd"); // the pinout on the mbed Cool Components workshop board

int main() {
    // set serial uart baud 115200
    uart.baud(115200);

    // set pc baud 115200
    pc.baud(115200);

    //  mkdir("/sd/MODSERIAL_vs_SDFileSystem/", 0777);
    //   sd_activity = !sd_activity;


    //   FILE *fp = fopen("/sd/MODSERIAL_vs_SDFileSstem/sdtest.txt", "w");
    //   if(fp == NULL) {
    //       error("Could not open file for write\n");
    //   }
    //   fprintf(fp, "Hello SD Card World!");

    //   fclose(fp);

    //  pc.printf("Goodbye World!\n");

    while (1) {
        myled = 1;
        wait(0.2);
        myled = 0;
        wait(0.2);
    }
}
08 Mar 2011

Alright I tried your first code snippet with out any of the SD includes and I had to hit compile and the reset on the mbed until it finally worked. Then I included the SD headers and I couldn't get anything (no lights) even after hitting compile and reset about 15 times.

08 Mar 2011

Tried second suggestion, no LED's blinking.

Will try to lower baud rate of UM6 maybe later.

08 Mar 2011

Daft question, is there an SD card in the CoolComp SD card slot?

08 Mar 2011

Yes there's a 1 gig card. I have ran the hello world SD card demo, and had no problems.

08 Mar 2011

NEVERMIND: I found the edit button in my profile, published programs page

Quick question how do I modify my published program. I wasn't worried about naming it right, so now it has the lame name Copyof_Buffered_UM6. I though I would be able to fix it later, but I can't find any way of editing it.

08 Mar 2011

Once published it remains. You can only delete it and re-publish again.

08 Mar 2011

I've made some progress. I don't have a UM6 so what I did was mock-up a quick program that uses MODDMA+MODSERIAL to send a buffer continuously and loop it back thro USB to my terminal. That worked fine. I then imported the SDFileSystem and added the #include "SDFileSystem.h" and created an sd instance.

All worked fine, my program worked. Then the crunch, I inserted a (previously known and functioning on Mbed+CoolComp) SD Card. Bang. It killed the Mbed stone dead. Removing the card from the slot brought the Mbed to life (without even pressing reset!).

So now I have something to work with to see why the SD library does this. But it's nearly 2am here now and bed calls. I'll resume tomorrow.

08 Mar 2011

Ok, I feel like were making some real progress now that is more in line with the topic of the thread, instead of just showing the world how little I now about interrupts.

08 Mar 2011

whoops, one step back. I was using p9/p10 for sending my test data. The CoolComp uses p9 for SD card detect, oops. So I switched my test to p28,p27 and it's now working as expected, ie not broken :( I'll look more tomorrow, obviously too tired!

08 Mar 2011

Thanks for all your help. After playing around with the servo library for awhile, I decided to try using Windows Vista and magically the mbed flash loader started working normally again. Long story short, the data from the UM6 IMU is being logged to the sd card using modserial and sdfilesystem.

Mission Accomplished: Now I only have a few things left to do:

  • Interface the GSM/GPS Telit GM862 GPS Module
  • Interface the DNT900 1W RF Modem
  • Interface the HS-785HB Winch Servos
  • Interface the Firgelli PQ12 Linear Actuator and H-bridge Driver
  • Implement a PID controller
  • And maybe a pitot tube sensor.

Thanks again, I learned my lesson about trying to keep coding when the flash loader is acting funny.

23 May 2013

Hi Ihiggs,

I've been using your code (thanks) from:

https://mbed.org/users/lhiggs/code/UM6_IMU_AHRS_2012/#

But I'd like to log file to sd card. Would you mind publishing your code for this? I think I'm having similar problems (but haven't fully gone through the above thread). - I've been trying to log 10-15 variables from um6 to a local file at a rate of 10ms, but the logging freezes. Works fine if I print to screen. I've published my code here:

https://mbed.org/users/njewin/code/UM6_IMU_AHRS_edit_NJE/

I'm also trying to connect a LS20031 GPS module via the um6. I've managed to modify your code to read the ground course and speed, but can't get the latitude and longitude to read out.

Cheers,

Nathan