c - Casting troubles when using bit-banding macros with a pre-cast address on Cortex-M3 -


tl;dr:

  1. why isn't (unsigned long)(0x400253fc) equivalent (unsigned long)((*((volatile unsigned long *)0x400253fc)))?
  2. how can make macro works former work latter?

background information

environment

i'm working arm cortex-m3 processor, lm3s6965 ti, stellarisware (free download, export controlled) definitions. i'm using gcc version 4.6.1 (sourcery codebench lite 2011.09-69). stellaris provides definitions 5,000 registers , memory addresses in "inc/lm3s6965.h", , don't want redo of those. however, seem incompatible macro want write.

bit banding

on arm cortex-m3, portion of memory aliased 1 32-bit word per bit of peripheral , ram memory space. setting memory @ address 0x42000000 0x00000001 set first bit of memory @ address 0x40000000 1, not affect rest of word. change bit 2, change word @ 0x42000004 1. that's neat feature, , extremely useful. according arm technical reference manual, algorithm compute address is:

bit_word_offset = (byte_offset x 32) + (bit_number × 4) bit_word_addr = bit_band_base + bit_word_offset 

where:

  • bit_word_offset position of target bit in bit-band memory region.
  • bit_word_addr address of word in alias memory region maps targeted bit.
  • bit_band_base starting address of alias region.
  • byte_offset number of byte in bit-band region contains targeted bit.
  • bit_number bit position, 0 7, of targeted bit

implementation of bit banding

the "inc/hw_types.h" file includes following macro implements algorithm. clear, implements word-based model accepts 4-byte-aligned words , 0-31-bit offsets, resulting address equivalent:

#define hwregbitb(x, b)                                               \     hwregb(((unsigned long)(x) & 0xf0000000) | 0x02000000 |               \            (((unsigned long)(x) & 0x000fffff) << 5) | ((b) << 2)) 

this algorithm takes base either in sram @ 0x20000000 or peripheral memory space @ 0x40000000) , ors 0x02000000, adding bit band base offset. then, multiples offset base 32 (equivalent five-position left shift) , adds bit number.

the referenced hwreg performs requisite cast writing given location in memory:

#define hwreg(x)                                                              \     (*((volatile unsigned long *)(x))) 

this works quite nicely assignments like

hwregbitw(0x400253fc, 0) = 1; 

where 0x400253fc magic number memory-mapped peripheral , want set bit 0 of peripheral 1. above code computes (at compile-time, of course) bit offset , sets word 1.

what doesn't work

unfortunately, aforememntioned definitions in "inc/lm3s6965.h" perform cast done hwreg. want avoid magic numbers , instead use provided definitions

#define gpio_portf_data_r       (*((volatile unsigned long *)0x400253fc)) 

an attempt paste hwregbitw causes macro no longer work, cast interferes:

hwregbitw(gpio_portf_data_r, 0) = 1; 

the preprocessor generates following mess (indentation added):

(*((volatile unsigned long *)     ((((unsigned long)((*((volatile unsigned long *)0x400253fc)))) & 0xf0000000)     | 0x02000000 |     ((((unsigned long)((*((volatile unsigned long *)0x400253fc)))) & 0x000fffff) << 5)     | ((0) << 2)) )) = 1; 

note 2 instances of

(((unsigned long)((*((volatile unsigned long *)0x400253fc))))) 

i believe these casts causing process fail. following result of preprocessing hwregbitw(0x400253fc, 0) = 1; work, supporting assertion:

(*((volatile unsigned long *)     ((((unsigned long)(0x400253fc)) & 0xf0000000)      | 0x02000000 |     ((((unsigned long)(0x400253fc)) & 0x000fffff) << 5)     | ((0) << 2)) )) = 1; 

the (type) cast operator has right-to-left precedence, last cast should apply , unsigned long used bitwise arithmetic (which should work correctly). there's nothing implicit anywhere, no float pointer conversions, no precision/range changes...the left-most cast should nullify casts right.

my question (finally...)

  1. why isn't (unsigned long)(0x400253fc) equivalent (unsigned long)((*((volatile unsigned long *)0x400253fc)))?
  2. how can make existing hwregbitw macro work? or, how can macro written same task not fail when given argument pre-existing cast?

1- why isn't (unsigned long)(0x400253fc) equivalent (unsigned long)((*((volatile unsigned long *)0x400253fc)))?

the former integer literal , value 0x400253fcul while latter unsigned long value stored in (memory or gpio) address 0x400253fc

2- how can make existing hwregbitw macro work? or, how can macro written same task not fail when given argument pre-existing cast?

use hwregbitw(&gpio_portf_data_r, 0) = 1; instead.


Comments

Popular posts from this blog

java - Play! framework 2.0: How to display multiple image? -

gmail - Is there any documentation for read-only access to the Google Contacts API? -

php - Controller/JToolBar not working in Joomla 2.5 -