0
votes

I am facing an issue in getting 2 LEDs glow one after another or at the same time. However, they work separately only one at a time. The problem comes when I try to achieve this in the same program. Only the first LED starts filckering not the other one. Following is my code:

#define GPFSEL1 0x20200004
#define GPFSEL2 0x20200008

#define GPSET0  0x2020001C
#define GPCLR0  0x20200028

#define SET_PIN18_OUTPUT (0x01 << 24) // GPFSEL1
#define SET_PIN23_OUTPUT (0x01 << 9)  // GPFSEL2
#define SET_PIN24_OUTPUT (0x01 << 12) // GPFSEL2

#define SET_GPION(x)   (0x01 << x)
#define CLEAR_GPION(x) (0x01 << x)

#define NUM_OF_LEDS 3

//-------------------------------------------------------------------------
typedef unsigned int* UINT32_P;

void dummy(volatile unsigned int val)
{
  val++;
}

void setBit(unsigned int regAdd, unsigned char bit)
{
  unsigned int temp;
  temp  = *(UINT32_P)(regAdd);
  temp  |= (0x1 << bit);
  *(UINT32_P)(regAdd) = temp;
}

void clearBit(unsigned int regAdd, unsigned char bit)
{
  unsigned int temp;
  temp = *(UINT32_P)(regAdd);
  temp &= ~(1 << bit);
  *(UINT32_P)(regAdd) = temp;
}

int notmain ( void )
{
    unsigned int ra;

    setBit(GPFSEL1, 24);  // Configure PIN 18 to output
    setBit(GPFSEL2, 12);  // Configure PIN 24 to output
    while(1)
    {
    // L1 - -
    setBit(GPSET0, 18);
    setBit(GPSET0, 24);
    for(ra=0;ra<0x100000;ra++) dummy(ra);


    // - L2 -
    setBit(GPCLR0, 18);
    setBit(GPCLR0, 24);
    for(ra=0;ra<0x100000;ra++) dummy(ra);

    for(ra=0;ra<0x100000;ra++) dummy(ra);



    }
    return(0);
}
3
You would do well to remove the unused redundant macros from this code - that is just a distraction to anyone who might be able to help you.Clifford
Style fixes: use uint32_t from stdint.h (C99), #define SET_GPION(x) (0x01 << (x)) (and unused), registers should be volatile to avoid compiler optimizationGoswin von Brederlow

3 Answers

3
votes

The GPIO peripheral has separate registers for setting (GPSET0) and clearing (GPCLR0) output pins so that you don't have to do read-modify-write operations. Writing to the GPSET register only sets the bits that are 1 while the bits that are 0 remain unchanged. And writing to the GPCLR register only clears the bits that are 1 while the bits that are 0 remain unchanged.

You should not be using your setBit() and clearBit() routines for setting and clearing GPIO outputs. Those routines might be appropriate for other peripherals that don't have separate registers for setting and clearing bits. But the read-modify-write operation is not appropriate for GPSET0 and GPCLR0. In fact the read-modify-write operation may actually be the source of your problem. It may be that GPSET0 and GPCLR0 always return 0x00000000 when you read them because it should never be necessary to read them. (I'm not sure of that, I'm just speculating.)

Instead of calling setBit() and clearBit() to set the GPIO outputs you should just write to GPSET0 or GPCLR0 directly. You don't need to read GPSET0 or GPCLR0 before writing to them. Because when you write to them, only the bits you set to 1 will change, the bits that you write to 0 will remain unchanged.

Try something like this:

// Set bits
*(UINT32_P)GPSET0 = (1 << 18);
*(UINT32_P)GPSET0 = (1 << 24);

// Clear bits
*(UINT32_P)GPCLR0 = (1 << 18);
*(UINT32_P)GPCLR0 = (1 << 24);
1
votes

In notmain() you never call clearBit(), only setBit().

The type:

typedef unsigned int* UINT32_P;

should be declared:

typedef volatile unsigned int* UINT32_P;

I would suggest defining your addresses as pointers rather than integers:

#define GPFSEL1 ((UINT32_P)0x20200004)
#define GPFSEL2 ((UINT32_P)0x20200008)

#define GPSET0  ((UINT32_P)0x2020001C)
#define GPCLR0  ((UINT32_P)0x20200028)

With set/clearBit taking a UINT32_P rather than an unsigned int. Then you won't need numerous casts.

The BCM2835 includes timer hardware that you would do better to utilise than "busy-loops".

0
votes

Each GPIO pin has 3 bits to select a function. You only set one of the three bits, the lowest, while leaving the upper two bits alone. So my guess is that at boot pin 18 has function 0 and pin 24 has function 2 (or so). You then configure pin 18 to function 1, so it works, but pin 24 to function 3, which does not.

You should write a function "void setFunction(uint32_t pin, uint32_t fn)" that, depending on pin, loads one of GPFSEL0/GPFSEL1/GPFSEL2, masks out the 3 bits for the specified pin, ors in the 3 bits specified in fn and finally writes it back to the register.

The other thing I spot, which was already mentioned above, is that GPSET0/GPCLR0 don't need a read-modify-write. Just write the bit you want to set/clear to them directly. It won't affect any other bits.