cancel
Showing results for 
Search instead for 
Did you mean: 

Code explanation

zamolan
Associate II
Posted on November 21, 2014 at 16:01

 Hi! 

 I would be glad if someone would explain the steps this code does in order to set up the AF9 on GPIOD for CAN pins. It is in a nice example, and I cannot figure it out why does the setting like this. 

void GPIO_PinAFConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_PinSource, uint8_t GPIO_AF)

{

  uint32_t temp = 0x00;

  uint32_t temp_2 = 0x00;

  

  /* Check the parameters */

  assert_param(IS_GPIO_ALL_PERIPH(GPIOx));

  assert_param(IS_GPIO_PIN_SOURCE(GPIO_PinSource));

  assert_param(IS_GPIO_AF(GPIO_AF));

  

  temp = ((uint32_t)(GPIO_AF) << ((uint32_t)((uint32_t)GPIO_PinSource & (uint32_t)0x07) * 4)) ;

  GPIOx->AFR[GPIO_PinSource >> 0x03] &= ~((uint32_t)0xF << ((uint32_t)((uint32_t)GPIO_PinSource & (uint32_t)0x07) * 4)) ;

  temp_2 = GPIOx->AFR[GPIO_PinSource >> 0x03] | temp;

  GPIOx->AFR[GPIO_PinSource >> 0x03] = temp_2;

}

#can-code
2 REPLIES 2
Posted on November 21, 2014 at 16:19

Each pin has a 1-to-16 multiplexor for internal peripherals, and subset of these are used.

16 settings can be represented as 4-bits. There are 16 pins on each GPIO bank. So 4x16 = 64 bits to represent the setting on all of the pins.

The 64-bit AFR is spread over 2 32-bit registers. AFR[0..1]

The code masks off the 4-bits associated with the specific pin, then or's on the specific mux setting for the peripheral to attach.

0690X00000603IgQAI.jpg
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
zamolan
Associate II
Posted on November 24, 2014 at 14:09

Thank you for the explanation! 

   So I would sum up what I did understood, in order to be clear for anybody who reads this thread : 

temp = ((uint32_t)(GPIO_AF) << ((uint32_t)((uint32_t)GPIO_PinSource & (uint32_t)0x07) * 4)) ;

GPIO_AF=b1001; is a byte encoding AF9 (9th Alternate Function option) for a PIN setting in AFR register for a specific Port. We need to shift these four bits (1001) to the PinSource on which we wish to use the peripheral (CAN in our case). Every calculation is made in 32 bit unsigned int format, since our AFR[x] is 32 bit wide too. 

To shift 4 bits to the nth pin, the narrowed down pin number is multiplied by 4, meaning we wish to move 4 bits more at every shift, not only a single bit, as a shifting procedure is usually working. 

 Since we set a single 32 bit register at a time, and such an AFR register decodes 8 pins on a port we want to know the nth pin on the lower, or the upper half of the PORT. 

&-ing the pin number with 0x07 practically gives the remainder of PinSource/8, which matematically means expressing '' I don't care the exact location of the desired PIN, just tell me relatively its position from a multiply of 8'' (since we have a set (2) registers addressing 8 pins, we will select the necessary group of 8 pins later). 

Therefore, temp will be a 32 bit register mask with value of 1001 shifted to the desired PINs setting position. 

GPIO_PinSource >> 0x03 decides the upper or lower half of the PORT. because the least significat bit from a byte halves the byte in two. Matematically means ''throw away 3 most significant bits out of the 4, we need only the least significant''. 

~((uint32_t)0xF << ((uint32_t)((uint32_t)GPIO_PinSource & (uint32_t)0x07) * 4))

Will set to 1111 the desired PINs AFR register position pins, then negates the whole 32 bit value, having 0000 only at the specific pins place. Like this, practically the following equation:

GPIOx->AFR[GPIO_PinSource >> 0x03] &= ~((uint32_t)0xF << ((uint32_t)((uint32_t)GPIO_PinSource & (uint32_t)0x07) * 4)) ;

Will delete ANY AF setting for the desired GPIO_PinSource residing in the AFR register ONLY.

Next equation writes the 1001 value into the freshly 0-ed position of the PIN setting. 

temp_2 = GPIOx->AFR[GPIO_PinSource >> 0x03] | temp;

Then rewrites the whole register part with the newly combined value. (

Though, I find the second temporary calculation unnecessary)