0

I'm working on Keil software and using LM3S316 microcontroller. Usually we address registers in microcontrollers in form of:

#define GPIO_PORTC_DATA_R       (*((volatile uint32_t *)0x400063FC))

My question is how can I access to single pin of register for example, if I have this method:

char process_key(int a)
{  PC_0 = a ;}

How can I get PC_0 and how to define it?

Thank you

Clifford
  • 88,407
  • 13
  • 85
  • 165
Matrix
  • 107
  • 1
  • 2
  • 9
  • 1
    masking and shifting. depending on the microcontroller some have ways to set or clear bits in a register without a read-modify-write. – old_timer May 25 '20 at 23:20
  • the cortex-m has a bit banding feature that you read about as well. – old_timer May 25 '20 at 23:23
  • @old_timer I looked at the [data sheet](http://www.keil.com/dd/docs/datashts/luminary/lm3s316.pdf), there do not appear to be bit set/bit reset registers in the GPIO map on LM3S316. – Clifford May 25 '20 at 23:39
  • yep, I did too, it appears for that part either read-modify-write with the data register or use bit banding if available. We are not hear to read the manuals for the OP, not the purpose of SO. – old_timer May 26 '20 at 02:16

1 Answers1

0

Given say:

#define PIN0 (1u<<0)
#define PIN1 (1u<<1)
#define PIN2 (1u<<2)
// etc...

Then:

char process_key(int a)
{  
    if( a != 0 )
    {
        // Set bit
        GPIO_PORTC_DATA_R |= PIN0 ;
    }
    else
    {
        // Clear bit
        GPIO_PORTC_DATA_R &= ~PIN0 ;
    }
}

A generalisation of this idiomatic technique is presented at How do you set, clear, and toggle a single bit?

However the read-modify-write implied by |= / &= can be problematic if the register might be accessed in different thread/interrupt contexts, as well as adding a possibly undesirable overhead. Cortex-M3/4 parts have a feature known as bit-banding that allows individual bits to be addressed directly and atomically. Given:

volatile uint32_t* getBitBandAddress( volatile const void* address, int bit )
{
    __IO uint32_t* bit_address = 0;
    uint32_t addr = reinterpret_cast<uint32_t>(address);

    // This bit maniplation makes the function valid for RAM
    // and Peripheral bitband regions
    uint32_t word_band_base = addr & 0xf0000000u;
    uint32_t bit_band_base = word_band_base | 0x02000000u;
    uint32_t offset = addr - word_band_base;

    // Calculate bit band address
    bit_address = reinterpret_cast<__IO uint32_t*>(bit_band_base + (offset * 32u) + (static_cast<uint32_t>(bit) * 4u));

    return bit_address ;
} 

Then you can have:

char process_key(int a)
{  
    static volatile uint32_t* PC0_BB_ADDR = getBitBandAddress( &GPIO_PORTC_DATA_R, 0 ) ;

    *PC0_BB_ADDR = a ;
}

You could of course determine and hard-code the bit-band address; for example:

#define PC0 (*((volatile uint32_t *)0x420C7F88u))

Then:

char process_key(int a)
{  
    PC0 = a ;
}

Details of the bit-band address calculation can be found ARM Cortex-M Technical Reference Manual, and there is an on-line calculator here.

Clifford
  • 88,407
  • 13
  • 85
  • 165
  • 1
    Just a nit-pick: make sure to always write `1u< – Lundin May 26 '20 at 10:59
  • @Lundin I would not be at all offended had you edited it - though not your job to fix my errors of course. Will fix. The bit band address code I copy and pasted from an old answer (of mine) elsewhere. I am pretty sure the version I currently use has better type agreement since it will have since been through static analysis - but I did not have access to that version at the time. Was missing the `0x` prefix on the PC0 def too - also fixed. – Clifford May 26 '20 at 11:14