NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Microcontroller Programming » Need help reading input port pin

September 12, 2012
by jlaskowski
jlaskowski's Avatar

I am using the ATmega168 to connect to a CC3000 (handles wireless communications) via SPI. The start up sequence for the CC3000 is to apply VCC, which it gets from the breadboard, then after a small delay, raise a CC3000 pin called power-enable (PWR_EN). Soon, the CC3000 will indicate readiness by bringing one of its other pins (SPI_IRQ) low.

I chose PC3 as an output pin to raise PWR_EN on the CC3000. I chose PC2 as an input pin to read SPI_IRQ from the CC3000.

SPI_IRQ goes from dead to GND after PWR_EN is raised. So, I have to activate the pull-up resistor on PC2 so that "dead" registers a 1 on PC2.

After VCC is applied, therefore, I should read SPI_IRQ (PC2) as high, which I do. After I raise PWR_EN, SPI_IRQ should go low. I tested it with an LED and then a voltmeter, and it is indeed going low, but I am not reading low on PC2 in the code. If you can tell what I'm doing wrong, let me know:

// configure Port C3 (CC3000 PWR_EN) as output
DDRC |= (1<<DDC3);

// configure Port C2 (CC3000 SPI_IRQ) as input
DDRC &= ~(1<<DDC2);

// activate the pull-up resistor on Port C2
PORTC |= (1<<PC2);

//check SPI_IRQ before PWR_EN
unsigned char spi_irq_value = PORTC & (1<<PC2);
if (spi_irq_value > 0) {
    turn_on_yellow();
} else {
    turn_on_green();
}
delay_ms(4000);    // extra delay to note LED color
turn_off_both_lights();

delay_ms(1000);      // delay between VCC and PWR_EN
PORTC |= (1<<PC3);  // power-enable the CC3000

while (1) {
    spi_irq_value = PORTC & (1<<PC2);
    if (spi_irq_value == 0) {
        turn_on_green();
        break;
    }
}

delay_ms(1000);
September 12, 2012
by pcbolt
pcbolt's Avatar

jlaskowski -

On line 25...

if (spi_irq_value == 0){

when this is true and the code following it gets executed, "break;" will put you outside the "while(1)" loop and effectively end the program. Just remove line 27. If you wanted to jump back to the start of the loop, use "continue;"

September 12, 2012
by jlaskowski
jlaskowski's Avatar

I just wanted to turn the green LED light on once and leave it on. In effect, it's saying, if PC2 is ever detected as low, turn on the light and break out of the loop.

Do you have any ideas why it wouldn't be reading PC2 as low in the code when the rail breadboard rail that PC2 is connected to is testing low? Are these lines the correct way to test the value?

spi_irq_value = PORTC & (1<<PC2);
if (spi_irq_value == 0) {
September 12, 2012
by pcbolt
pcbolt's Avatar

Those lines of code in your last post are ok. When you break out of the while loop the MCU will no longer exectute anything so you do not know if the MCU detected a low value or not. I think what you want to do is create a flag variable to that gets changed once the light goes on. Something like...

uint8_t green_on = 0;
while(1){
  if (green_on == 0){
    spi_irq_value = PORTC & (1<<PC2);
    if (spi_irq_value == 0) {
      turn_on_green();
      green_on = 1;
    }
  }
}
September 12, 2012
by jlaskowski
jlaskowski's Avatar

I think I confused you with the LED business. I have a yellow LED on PC5 (output) and a green LED on PC4 (also output). The function turn_green_on() turns off the yellow LED and turns on the green LED. The function turn_yellow_on does the opposite. The function turn_off_both_lights() does as it is named. I didn't show the setup code for those ports or the code for those methods.

When the code above runs, it sets up two additional ports, PC3, an output to CC3000's PWR_EN, and PC2, an input from CC3000's SPI_IRQ. PC3 has a pull-up resistor enabled because, before I raise PWR_EN, SPI_IRQ is an open circuit and afterward it goes to GND. So, that means on startup, PC2 is pulled high. In the code above, I check the value of PC2 first and turn on the yellow LED if it's high, green LED when it's low. It is high as expected.

Next, I turn the lights off, raise PWR_EN and then go into the loop, testing PC2 to see if the CC3000 ever changes SPI_IRQ from open-circuit to GND. If any of my iterations find PC2 to be low, I turn the green LED on and break out of the loop. I then go into an infinite loop doing nothing but waiting (not shown in the code above). Therefore, if PC2 ever goes low after I raise PWR_EN, the green light should turn on and stay turned on. Unfortunately, it never happens, despite physical tests that prove SPI_IRQ is going from open circuit to GND.

To see whether SPI_IRQ was going from open circuit to GND, I took an additional LED (which has nothing to do with the functions above) and put its cathode on PC2 and anode on the +5 rail. Then I ran the code again and just after I turned on PWR_EN, the LED turned on, proving that SPI_IRQ went from open-circuit to GND as the CC3000 claims it should. I then used a voltmeter and saw the voltage go from +5 to 0 after I raised PWR_EN.

September 12, 2012
by jlaskowski
jlaskowski's Avatar

I just figured it out. I have to read PC2 like this:

spi_irq_value = PINC & (1<<PC2);

not like this:

spi_irq_value = PORTC & (1<<PC2);

which just reads the fact that I set PC2 high earlier on PORTC in order to enable the pull-up resistor, by this:

// activate the pull-up resistor on Port C2
PORTC |= (1<<PC2);
September 12, 2012
by Noter
Noter's Avatar

So the green light never comes on? Maybe something wired wrong with the green light?

September 12, 2012
by pcbolt
pcbolt's Avatar

@ jlaskowski

No the LED business did not confuse me, it was

  • "I then go into an infinite loop doing nothing but waiting (not shown in the code above)

I thought your code ended right after the while(1) loop. Yep PINC should do it. Hope all turns out well...keep us posted.

Post a Reply

Please log in to post a reply.

Did you know that reading a double floating point variable with scanf requires "%lf" for "long float"? Learn more...