This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP430F2013/ FG4618 I2C

Hello,

I'm writing a program to detect the key_pressed on the touch pad (capsense). But it is interrupt driven. So how do I know which key on port1 is pressed.

Further, are the F2013 and FG4618 configured as slave and master by default.

 

Regards,

Krishna.

 

 

  • There is a difference between keypresses on port 1 and the capsense detection.

    'Digital' keypresses on port 1 are detected by programming the port pin for an edge interrupt. You can read which port pin was triggered by reading the IFG register. The pin that was triggered has its IFG bit set.

    The capsense keypresses are done by charging and discharging a capacitor formed by the pad. Here the pad has an initial capacitance (unpressed) which significantly increases when you touch the pad. The MSP loads and discharges the pad and checks the timing. If it takes suddenly longer to charge and discharge the pad, teh capacitance has increased because the pad has been touched.

    There's a whole appnote available on the TI website about this.

    Krishna Thallapaka said:
    are the F2013 and FG4618 configured as slave and master by default.

    Yes. The F2013 is not only configured as slave by default (which you can easily change by changing the software), but the SPI connection is also routed in a way that it works only this way. The reason is that the USCI module in teh 4618 changes its data direction based on the role (SOMI and SIMO pins - Slave Out Master In etc.) while the USI module in the 2013 always outputs on one pin and receives on teh other, independently of the role. So if you want the 2013 to be the SPI master, you'll need to cross the connections.

  • Hello Gross,

    You stated that there is a difference between key_press detection on port1 and capsense detection. I'm unable to see a difference, because:

    - Placing my finger on the touch pad would generate an interrupt when the capacitance discharge crosses a threshold. Then its a question of finding out which port pin value has changed by checking the IFG register, because each port pin is connected to three pads.

    Coming to the second question, I'm using I2C and not SPI. In I2C mode, I believe that the F2013 can be configured as master Transmitter and FG4618 as slave receiver. I'm using USI mode for F2013.

     

    Regards,

    Krishna.

     

     

     

  • Hello Gross,

    To detect the pin (on which interrupt occurred), I wrote the following:

    #pragma vector=PORT1_VECTOR
    __interrupt void port_1_interrupt(void)
    {
      char active_key;
     
      for (char key = 0; key < Num_Sens; key++)
      {
       active_key = 1 << key;  
     
       if(P1IFG == active_key)
         key_loc = key;
      }

     P1IFG = 0;                           
        
      LPM3_EXIT;                           
    }

     

    The above did not work. Say I touched a pad connected to port P1.1. Then I expected P1IFG to be equal to 0x02. But that is not happening; I see values like 0x3C.

     

    Regards,

    Krishna.

  • Krishna Thallapaka said:
    The above did not work. Say I touched a pad connected to port P1.1. Then I expected P1IFG to be equal to 0x02. But that is not happening; I see values like 0x3C.

    That's the difference between touch sense and pushbutton detection.

    You're right, in both cases you see the voltage crossing an edge. But in button mode, the edge only happens the moment the button is pressed, and the opposite edge when the button is released (maybe with bouncing, so you might need some debounce code). It's passive sensing. If nothing happenns, then nothing happens.

    In a capsense applicaiton, the capacitor is constantly charged and discharged, so you'll always see an edge on all lines, whether someone is pressing the button or not. What changes is the time between the begin of the cyclic discharge and the moment the threshold is crossed (touch = larger capacitance = larger discharge time). It will always happen over and over again. The question is not whether but when. It's active polling the sensor, and only by the time it takes to reach tehe trigger point you can tell whether there was a touch or not.

    Bout the I2C transmission, I don't have any experience with the I2C mode on teh 2013. And to be honest, I foudn the description so complicated and th eusage so clumsy that I'd prefer writing my own bit-banging code when I want to program an I2C master. I also did so on the 1611 instead of using the USART module, even if the USART is way easier to handle than the USI.
    The USCI I2C, however, is really usable and I already use it.

  • Hello Gross,

     

    To quote you:

    "It's active polling the sensor, and only by the time it takes to reach the trigger point you can tell whether there was a touch or not."

    reply: When I touch the pad, the program jumps into the Interrupt Service Routine. So within the routine, I can write 'key_pressed = 1'. The question is not whether I touched the pad. The question is the associated pin. Since each pad is connected to a pin on port1, I want to know the pin in question.

               The pin in question -- can it be known by reading the P1IFG register -- because P1IFG is ending up with strange values.

               I cannot use polling, because, say for e.g. I touch a pad which is connected to P1.4, but the for loop is still processing for a pad connected to P1.0. Then a change in capacitance will generate an interrupt on P1.4 and cause the Interrupt Service Routine to execute.

     

    The below code may illustrate the same:

    __________________________________________________________________

     for(char key = 0; key < number_of_sensors; key ++)

      {

       active_key =  1 << key;

       P1OUT = ~(BIT0 + BIT1 + BIT2 + BIT3);

       P1OUT |= active_key; // charge the respective pin

        _NOP(); // allow time to charge
        _NOP();
        _NOP();

          P1IES |= active_key;                //-ve edge trigger
          P1IE |= active_key;

     }


    #pragma vector=PORT1_VECTOR
    __interrupt void port_1_interrupt(void)
    {
      char active_key;
     
      for (char key = 0; key < Num_Sens; key++)
      {
       active_key = 1 << key; 
     
       if(P1IFG == active_key)
         key_loc = key;
      }
       P1IFG = 0;                            // clear flag
     
       
      LPM3_EXIT;                            // Exit LPM3 on reti
    }

     ________________________________________________________________

     

     

     

  • Further, the user guide states that P1IFG is affected whenever we write to P1OUT, P1DIR, P1IES registers. But I don't see that happen in the above code.

     

    Regards,

    Krishna.

  • Krishna Thallapaka said:
    reply: When I touch the pad, the program jumps into the Interrupt Service Routine.

    You still missed the point: on touch rcognition, there will ALWAYS be a trigger in regular intervals. The difference between touched or not is not whether the interrupt comes, but with which frequency it comes. High frequency: no touch, lower frequency: touch.

    So you need to measure the intervall between two itnerrupts and decide whether it is long enough to indicate a touch (touch = increased capacitance = low charge speed = low interrupt frequency; no touch: base capacitance = higher charge speed = higher interrupt frequency)

    What you described (and programmed) works for a pushbutton that applies a sudden voltage level change to the port pin when pressed. It is an active component and you jsut can wait passively until the event happens. capacitive touch sensing is a completely different thing. Here the pad is passive and you need to actively check the capacitance over and over again. A change of capacitance (and we speak about a few pF here) will by itself not cause any detectable voltage change and therefore no itnerrupt.

    Krishna Thallapaka said:
    The pin in question -- can it be known by reading the P1IFG register -- because P1IFG is ending up with strange values.

    Yes. Each bit in this register corresponds to one physical port pin. So if a pin has detected an edge and caused an interrupt, you can see its coresponding bit set in this register (the bits are set even if there was no interrupt caused because the IE bit was not set for this pin). Some MSPs have an additional interrupt vector register. Here you can fetch the number of the highest interrupt-causing pin. Only those pins where the IE bit was set (and therefore realyl caused an itnerrupt) are output by this register.

    However, the timing is a critical thing. That's why I did my own touch applicaiton in a completely different way:

    I use a timer and its CCR units. I use TiemrB because I can limit the size of the timer register to 12 bit. And it has 7 CCR units on the 5438, allowing me to support 6 pads.

    I let the timer count  in continuous mode form 0 to 4095 and then 0 again.
    CCR0 is set to 0, toggle mode. Tha tmeans, on each timer overflow the TB.0 output toggles. This output signal is routed to the touch pads through a diode each (I used BAT42. Low reverse current and fast reaction is essential). So when the TB.0 output goes high, it charges the pads throught he diodes. When the output goes low, the charging stops. The pads are connected ot the other CCR units in capture mode. The pads discharge now through the diode and the port inputs (leakage current). The voltage will eventually drop down to the trigger level and trigger the capture event for the CCR units.
    The higher the CCR reading of these units, the longer it too to discharge the pad and higher the capacitance of the pad was. A sudden increase of the time required for discharge indicates a touch.

    This way I can measure 6 pads at the same time with no code required. I can just read the value of one of the CCR registers when I want to know whether a certain pad had been pressed. The only difficult thing is the calibration. :)

     

    Krishna Thallapaka said:
    Further, the user guide states that P1IFG is affected whenever we write to P1OUT, P1DIR, P1IES registers. But I don't see that happen in the above code.

    'affected' does not mean that something will happen, only that it might happen. e.g. changing the edge to detect may cause an immediate interrupt even if there was no change on the pin signal level. Just the detection circuitry has been reprogrammed and now detects a virtual change. It depends on what oyu do and what the current input signals are. Also, writing to P1OUT will of course chenge the signal level and perhaps cause an interrupt, and so possibly will do a deactivation of the output by swithcing the pin to input.

  • Hello Gross,

     

    To quote you:

       "The difference between touched or not is not whether the interrupt comes, but with which frequency it comes. High frequency: no touch, lower frequency: touch.

    So you need to measure the interval between two interrupts and decide whether it is long enough to indicate a touch (touch = increased capacitance = low charge speed = low interrupt frequency; no touch: base capacitance = higher charge speed = higher interrupt frequency)"

     

    What  I made out from the above statements was:

    "As long as the pad is pressed, the program remains within the Interrupt Service Routine; so in the code below, the timer_cnt value keeps increasing. When I take off my finger, the program exits the routine."


    for(i = 0; i < number_sensors; i++)

    {

     ...

     ...


     timer_cnt = TAR;

     P1IES &= ~active_key;               

     P1IE |= active_key; // At this point, the program jumps into the interrupt service routine.

    }


    #pragma vector=PORT1_VECTOR
    __interrupt void port_1_interrupt(void)
    {
      P1IFG = 0;                            // clear flag
      timer_cnt = TAR - timer_cnt;      // find the charge/discharge time
      LPM3_EXIT;                            // Exit LPM3 on reti
    }

     

    Regards,

    Krishna.

     

  • Krishna Thallapaka said:

    What  I made out from the above statements was:

    "As long as the pad is pressed, the program remains within the Interrupt Service Routine; so in the code below, the timer_cnt value keeps increasing. When I take off my finger, the program exits the routine."

    No. The program will not remain inside the ISR. it will enter the ISR 100 times (or whatever) per second if there is no touch and less often when there IS a touch. But it will always enter the ISR periodically, whether there is a touch or not. So you counte rwill increase by 100 counts per second if there is no touch and only by 50 per second if there is a touch.

    You don't need to check whether the ISR is entered, but how much time has passed since it was entered the last time. The longer the time between two interrupts, the nearer the finger is to the pad.
    Determining the min and max value belongs to the calibration process.

**Attention** This is a public forum