WIZnet Developer Forum

Is it wrong or I misunderstood in GPIO introduction

in the introduction on GPIOhttp://wizwiki.net/wiki/doku.php?id=products:w7500:peripherals:gpio


to set bits[1:0] to 1 and clear bits[7:6] in a single operation, there is b1100_0011(0XC3) and why the MSB is 0xC? Is it wrong or something I have misunderstood?

It is not wrong, the mask is used to define which bit(s) you want to modify. So, to change bits 0,1,6, 7 you create a mask with this bits to ‘1’ (bits 0 and 1 = 0x03 … bits 7 and 6 = 0xC0) ; then after you write a 8 bits value but only the bits set to 1 into the mask are used … it more or less like network mask used to compute network adresse from ip address.

MASK = [color=#FF0000]11[/color]00 00[color=#FF0000]11[/color]
VALUE = [color=#0000FF]00[/color]00 00[color=#0000FF]11[/color]
new GPIO port value = 00xx xx11 (where x values are unchanged)

The mask is not really a register but an array of address. The GPIO peripheral will use a part of the adress to compute the mask. So, to define a mask, you shift the mask value two bits left and you add the array offset.
Example to set the blue led of wizwiki board, connected on GPIO port-C bit 5 :
GPIO-C is at 0x44000000
Lower bits array (bit0 to bit7) is at 0x400 offset
To change only bit5, you create a mask : 0010 0000 (or 0x20)
You shift two bits to get mask address : 1000 0000 (0x80)

Then to set gpio to ‘1’ (led OFF) you write value 00[color=#0000FF]1[/color]0 0000 at adresse 0x44000000 + 0x400 + 0x80 (=0x44000480)
*(volatile unsigned long *)0x44000480 = 0x20;
Then to set gpio to ‘0’ (led ON) you write value 00[color=#0000FF]0[/color]0 0000 at adresse 0x44000000 + 0x400 + 0x80 (=0x44000480)
*(volatile unsigned long *)0x44000480 = 0x00;

Is it clear ?

[quote=“Hooligan0”]It is not wrong, the mask is used to define which bit(s) you want to modify. So, to change bits 0,1,6, 7 you create a mask with this bits to ‘1’ (bits 0 and 1 = 0x03 … bits 7 and 6 = 0xC0) ; then after you write a 8 bits value but only the bits set to 1 into the mask are used … it more or less like network mask used to compute network adresse from ip address.

MASK = [color=#FF0000]11[/color]00 00[color=#FF0000]11[/color]
VALUE = [color=#0000FF]00[/color]00 00[color=#0000FF]11[/color]
new GPIO port value = 00xx xx11 (where x values are unchanged)

The mask is not really a register but an array of address. The GPIO peripheral will use a part of the adress to compute the mask. So, to define a mask, you shift the mask value two bits left and you add the array offset.
Example to set the blue led of wizwiki board, connected on GPIO port-C bit 5 :
GPIO-C is at 0x44000000
Lower bits array (bit0 to bit7) is at 0x400 offset
To change only bit5, you create a mask : 0010 0000 (or 0x20)
You shift two bits to get mask address : 1000 0000 (0x80)

Then to set gpio to ‘1’ (led OFF) you write value 00[color=#0000FF]1[/color]0 0000 at adresse 0x44000000 + 0x400 + 0x80 (=0x44000480)
*(volatile unsigned long *)0x44000480 = 0x20;
Then to set gpio to ‘0’ (led ON) you write value 00[color=#0000FF]0[/color]0 0000 at adresse 0x44000000 + 0x400 + 0x80 (=0x44000480)
*(volatile unsigned long *)0x44000480 = 0x00;

Is it clear ?[/quote]

Thank you, Hooligan0, I am very appreciate with your kindly explain.And I have test it with a little more and made it successfully.This time I want to set the Green led, connected on GPIO port-C bit 9:
GPIO-C is at 0x44000000
[color=#FF4000]Higher[/color] bits array (bit15 to bit8) is at 0x800 offset
To change only bit9, I create a mask : 0000 0010 0000 0000(or 0x0200)
shift two bits to get mask address :0000 1000 0000 0000(or 0x0800)([color=#FFBF00]Here I still don’t know why two bits, can you give me some reference[/color]?)
Then to set gpio to ‘1’ (led OFF) I write value 0000 00[color=#0000FF]1[/color]0 0000 0000 at adresse 0x44000000 + 0x800 + 0x0800 (=0x44001000)
*(volatile unsigned long *)0x44001000 = 0x0200;

Then to set gpio to ‘0’ (led ON) I write value 0000 00[color=#0000FF]0[/color]0 0000 0000 at adresse 0x44000000 + 0x800 + 0x0800 (=0x44001000)
*(volatile unsigned long *)0x44001000 = 0x0000;

#include "W7500x_gpio.h"

GPIO_InitTypeDef GPIO_InitDef;

void delay_ms(__IO uint32_t nCount);

int main()
{
    SystemInit();
        
    /* GPIO LED(G) Set */
    GPIO_InitDef.GPIO_Pin = GPIO_Pin_9; // Set to Pin_9 (LED(G))
    GPIO_InitDef.GPIO_Mode = GPIO_Mode_OUT; // Set to Mode Output
    GPIO_Init(GPIOC, &GPIO_InitDef);
    PAD_AFConfig(PAD_PC,GPIO_Pin_9, PAD_AF1); // PAD Config - LED used 2nd Function
		
    GPIO_SetBits(GPIOC, GPIO_Pin_9); // LED(G) Off
	
    while(1)
    {
        
        // LED(G) On
        delay_ms(500);
//        GPIO_ResetBits(GPIOC, GPIO_Pin_9);
				*(volatile unsigned long *)0x44001000 = 0x0000;
        delay_ms(500);
//        GPIO_SetBits(GPIOC, GPIO_Pin_9);	
				*(volatile unsigned long *)0x44001000 = 0x0200;
    }
}

void delay_ms(__IO uint32_t nCount)
{
    volatile uint32_t delay = nCount * 2500; // approximate loops per ms at 24 MHz, Debug config
    for(; delay != 0; delay--)
        __NOP();
}


[quote=“Yake”]This time I want to set the Green led, connected on GPIO port-C bit 9:
GPIO-C is at 0x44000000
[color=#FF4000]Higher[/color] bits array (bit15 to bit8) is at 0x800 offset
To change only bit9, I create a mask : 0000 0010 0000 0000(or 0x0200)
shift two bits to get mask address :0000 1000 0000 0000(or 0x0800)([color=#FFBF00]Here I still don’t know why two bits, can you give me some reference[/color]?)
[/quote]
Why two bits shift : Short answer
Because you use memory address to represent the mask ; and it’s better (and really more simple) to use aligned access.

Why two bits : Long answer
The mask array is a simple and powerfull solution to have two informations into one memory access. The first information is the mask, the second is the value herself.
First, imagine the question without shift. If you want to change bit0 of any port to ‘1’. You create a mask (0000 000[color=#0000FF]1[/color] or 0x01) and you use it directly as array index : you will have 0x400 + 0x01 = 0x401 as offset. Then you write at this memory location : *(volatile unsigned long *)(PORT + 0x401) = 0x01 Because of the “unsigned long” type you will write 4 bytes (at addresses 401, 402, 403, 404). The first problem of doing this is that you overlay other mask values (because 0x402 is the mask produced for bit1 in our example). The second problem is that you made an unaligned memory access (it is really simpler to align all peripheral access on 32 bits values [1])

To avoid this, Wiznet has made the choice to convert each mask values to 32 bits memory locations. So, to convert a mask value to a memory offset value you must multiply the mask value by 4. A 2 bit shift is the same than multiply by 4.

The array offset problem
You have made a really small error into offset value computation.
Your mask is 0000 00[color=#0000FF]1[/color]0 0000 0000(or 0x0200) it’s right … BUT … The higher mask array will use only the higher bits. So the array offset is 0000 00[color=#0000FF]1[/color]0 = 0x02 (bits 15 to 8) with two bits shift = 0x08
Green led mask will be : 0x44000000 + 0x800 + 0x08

/* Green led ON */ *(volatile unsigned long *)0x44000808 = 0x00; /* Green led OFF */ *(volatile unsigned long *)0x44000808 = (1 << 9);

[1] infocenter.arm.com/help/index.js … FAIGG.html

[quote=“Hooligan0”][quote=“Yake”]This time I want to set the Green led, connected on GPIO port-C bit 9:
GPIO-C is at 0x44000000
[color=#FF4000]Higher[/color] bits array (bit15 to bit8) is at 0x800 offset
To change only bit9, I create a mask : 0000 0010 0000 0000(or 0x0200)
shift two bits to get mask address :0000 1000 0000 0000(or 0x0800)([color=#FFBF00]Here I still don’t know why two bits, can you give me some reference[/color]?)
[/quote]
Why two bits shift : Short answer
Because you use memory address to represent the mask ; and it’s better (and really more simple) to use aligned access.

Why two bits : Long answer
The mask array is a simple and powerfull solution to have two informations into one memory access. The first information is the mask, the second is the value herself.
First, imagine the question without shift. If you want to change bit0 of any port to ‘1’. You create a mask (0000 000[color=#0000FF]1[/color] or 0x01) and you use it directly as array index : you will have 0x400 + 0x01 = 0x401 as offset. Then you write at this memory location : *(volatile unsigned long *)(PORT + 0x401) = 0x01 Because of the “unsigned long” type you will write 4 bytes (at addresses 401, 402, 403, 404). The first problem of doing this is that you overlay other mask values (because 0x402 is the mask produced for bit1 in our example). The second problem is that you made an unaligned memory access (it is really simpler to align all peripheral access on 32 bits values [1])

To avoid this, Wiznet has made the choice to convert each mask values to 32 bits memory locations. So, to convert a mask value to a memory offset value you must multiply the mask value by 4. A 2 bit shift is the same than multiply by 4.

The array offset problem
You have made a really small error into offset value computation.
Your mask is 0000 00[color=#0000FF]1[/color]0 0000 0000(or 0x0200) it’s right … BUT … The higher mask array will use only the higher bits. So the array offset is 0000 00[color=#0000FF]1[/color]0 = 0x02 (bits 15 to 8) with two bits shift = 0x08
Green led mask will be : 0x44000000 + 0x800 + 0x08

/* Green led ON */ *(volatile unsigned long *)0x44000808 = 0x00; /* Green led OFF */ *(volatile unsigned long *)0x44000808 = (1 << 9);

[1] infocenter.arm.com/help/index.js … FAIGG.html[/quote]

I really enjoy it, Thank you again.
Now, my question is: after I have test with the two code, the result is same, both of them can flash the green led.
I have use the break point but didn’t get the point.Thank you for patience.

[quote=“Yake”]I really enjoy it, Thank you again.
Now, my question is: after I have test with the two code, the result is same, both of them can flash the green led.
I have use the break point but didn’t get the point.Thank you for patience.[/quote]

i’m sorry but i don’t understand your new question. What are the “two code” you talk about ?

[quote=“Hooligan0”][quote=“Yake”]I really enjoy it, Thank you again.
Now, my question is: after I have test with the two code, the result is same, both of them can flash the green led.
I have use the break point but didn’t get the point.Thank you for patience.[/quote]

i’m sorry but i don’t understand your new question. What are the “two code” you talk about ?[/quote]

sorry the test code is below:

[code] while(1)
{

    // LED(G) On
    delay_ms(500);

// *(volatile unsigned long *)0x44000808 = 0x00;
*(volatile unsigned long *)0x44001000 = 0x00;
delay_ms(500);
// *(volatile unsigned long *)0x44000808 = (1 << 9);
*(volatile unsigned long *)0x44001000 = (1 << 9);
}[/code]

the comment one and the uncomment have the same effect.Both of them will flash the green light, it is wired.

[quote=“Yake”] *(volatile unsigned long *)0x44001000 = 0x00; *(volatile unsigned long *)0x44001000 = (1 << 9);
[/quote]

The valid registers for GPIO peripheral are between 0x44000000 and 0x44000BFF (see table 16, GPIOC register map, reference manual page 258)

I think upper bits are simply not conected into peripheral (lawrence may confirm if i’m right) So when you write at offset 0x1000 , the peripheral will decode address 0x0000 (bit 12 ignored). If you write at 0x44000000 this is GPIOC_DATA register. Into the reference manual, this register is used to read port, and bits are “read only” but, i’ve tested to write into, and this change the port value. I don’t know if it is a bug or just a side effect.

Copyright © 2017 WIZnet Co., Ltd. All Rights Reserved.