Search code examples
embeddedmicrocontrollerkeiladdressing

Addressing pins of Register in microcontrollers


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


Solution

  • 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.