Hallo,

Stel ik heb een 32bit controller, en deze heeft een register met GPIO. Elke GPIO pin heeft 2bits van het register voor de tristate instelling. Bijvoorbeeld:
00 = uit.
01 = aan.
10 = ingang.
11 = reserved.

Pin 1 = bit 0-1
pin 2 = bit 2-3
ect...

Hoe kan ik nu in C een define maken voor pin 1, waarbij ik alle 2 de bits kan instellen?
Pseudo van mijn idee,

in de H file
#define GPIO_1 0x000001 & 0x00000003

In de C file
GPIO_1 = 2;

Geen #define gebruiken maar bit-fields gebruiken.
Kijk even in je C documentatie.

Bitfields is ongeveer het slechtste wat je kunt gebruiken, totaal niet portable.

Beter is defines maken voor de states:


#define OFF 0x00
#define ON 0x01
#define INPUT 0x02

En dan eenzelfde truukje als bij de AVR toepassen met een macro:


#define GPIO(a, b) (b << (a*2))

Om de waarde te schrijven:


*iomemlocatie = GPIO(2, ON);

etc.

Zoiets moet je in elkaar knutselen.

Voor OFF/ON etc zou je ook een prefix kunnen zetten dat het duidelijk is dat het bij de GPIO's hoort.

Uiteraard moet je read/modify writes doen om de vorige waarde van de andere pinnen niet kwijt te raken.
Dan wordt het al een beetje lastiger (bits per 2 masken) en maak je beter een functie die het allemaal netjes voor je doet.
Bijvoorbeeld:
setGpioPinMode(int pin, enum PinMode mode)

Waarbij je voor 'mode' dan ook net zo goed een enum kunt maken met de fixed waarden:


enum PinMode {
  on = 0;
  off = 1;
  input = 2;
}

@henri62, Dat was mn backup plan :)
Het enige nadeel is dat dit maar een kant op werkt, of ik moet een aparte get/set maken.

Ik weet niet precies waar je op doelt met "portable", maar het word toch voor maar een specifieke processor gebruikt. Dus dat maakt niet uit. Daarnaast werkt een andere processor weer anders. De adressen zijn niet hetzelfde, of compleet anders ingedeeld. (Ik neem aan dat je dat bedoeld?)

Ik zal eens wat proberen met bitfields, Als dat niet werkt dan word het toch iets met macro's.

EDIT:
Get word toch een get/set. De rest van de processor is ook op die manier ingedeeld. Deze heeft voor de GPIO een set en reset register.

Uiteraard zijn alle tips en tricks welkom.

[Bericht gewijzigd door hardbass op (12%)]

Welke processor?

Want als het een STM32 ding is, daar is gewoon een prima library voor.
(en die heeft bovendien set/reset registers, zodat je met een enkele instructie individuele IO's kunt zettten, zonder read/modify/write (waarvoor je interrupts uit moet zetten))

Het gaat om de rpi dat ding heeft een BCM2835. Ik ben bezig om hem te programmeren zonder linux. Het lukt al aardig. De compiler is een "arm-none-eabi-gcc". Het lukt al om een led te laten knipperen.

Nu wil ik met de uart gaan spelen :)

Maak een define die "set_gpio" heet,


#define GPIO_UIT 0 
#define GPIO_AAN 1
#define GPIO_INPUT 2

#define set_gpio(pin) GPIO_DATAREG = (GPIO_DATAREG & ~(3<<(pin*2))) | (GPIO_AAN << (pin*2))
#define clr_gpio(pin) GPIO_DATAREG = (GPIO_DATAREG & ~(3<<(pin*2))) | (GPIO_UIT << (pin*2))
#define input_GPIO(pin) GPIO_DATAREG = (GPIO_DATAREG & ~(3<<(pin*2))) | (GPIO_INPUT << (pin*2))

Uit m'n hoofd is dat GPIO_DATAREG dan nog afhankelijk van het pinnummer, omdat pinnummers boven de 16 komen.

Je kan ook op github even zoeken naar bw_rpi_tools. Ik heb het ooit ook eens geschreven voor het eggie, welliswaar onder Linux, maar voordat er support voor gpio in Linux zat. Mijn code mmapt dus gewoon de GPIO module en duwt zelf de bits in het rond. Worst case heb ik het er uit gesloopt uit de huidige versie, dus dan moet je terugzoeken in de historie... (1e versie zat dit al in!)

Voor de mensen die nog willen weten wat ik uiteindelijk heb gedaan.

Nu hoef ik niet eerst uit te zoeken bij welke register welke IO hoort. Ik kan gewoon het io nummer gebruiken.

Mijn manier van variabelen declareren,
u8 = unsigned 8 bit

C file


void GPIO_Function(u8 gpioPin, u8 function)
{
	u8 reg = gpioPin / 10;				//Find the register 
	u8 shift = (gpioPin % 10) * 3;		//Find the first of the 3 bits
	u32 mask =(0x07 << shift);			//Create mask
	
	GPIO_REG_FSEL[reg] &= ~(mask);			//First reset all bits
	GPIO_REG_FSEL[reg] |= ((function << shift) & mask);	
	return;
}

void GPIO_Set(u8 gpioPin)
{
	u8 reg = gpioPin / 32;
	u32 bitNo = gpioPin % 32;
	
	GPIO_REG_SET[reg] |= (1<<bitNo);
	return;
}

void GPIO_CLR(u8 gpioPin)
{
	u8 reg = gpioPin / 32;
	u32 bitNo = gpioPin % 32;
	
	GPIO_REG_CLR[reg] |= (1<<bitNo);
	return;
}

h file


//Define registers
#define GPIO_REG_FSEL		((volatile u32 *) 0x20200000UL)
#define GPIO_REG_SET		((volatile u32 *) 0x2020001CUL)
#define GPIO_REG_CLR		((volatile u32 *) 0x20200028UL)


//Define hardware
#define GPIO_ACTLED		16		//GPIO pin 18


void GPIO_Function(u8 gpioPin, u8 function);
void GPIO_Set(u8 gpioPin);
void GPIO_CLR(u8 gpioPin);

Ja dat is inderdaad wat ik zo'n beetje bedoelde. Gewoon een nette functie maken. Waarom staat bij die bovenste functie een deelfactor van 10? Is wat vreemd.

Op 17 december 2015 22:13:47 schreef hardbass:
Mijn manier van variabelen declareren,
u8 = unsigned 8 bit

Verder: Stop aub met het zelf definieren van allerlei fixed width variablen (u8 en dat soort ellende wat ik overal tegen kom).
Gebruik de C99 stdint, die zijn daarvoor bedoeld.
#include <stdint.h>
Dus "uint8_t" . Maakt de code netjes portable.

[Bericht gewijzigd door henri62 op (17%)]

Die 10 deel factor heeft te maken met dat er 10 gpio per register worden gebruikt. Daarmee zoek ik dus de juiste register op.

Ik zie het: er zitten 3 bits in voor de pin-mode, voor 10 registers kom je dan uit op 30 bits. 2 bits in dat register ongebruikt waarschijnlijk.