¿Hay alguna forma de escribir un código GPIO genérico para MSP430?

2

Actualmente estoy trabajando en una placa MSP430 y estoy tratando de crear bibliotecas para poder usarlas fácilmente en mi proyecto. Estoy empezando con las funciones básicas de E / S digital.

Diga, por ejemplo, que necesito configurar P1.0 ON. En ese caso, normalmente lo que hago es:

P1SEL &= (~BIT0);           // Set P1.0 SEL for GPIO
P1DIR |= BIT0;              // Set P1.0 as Output
P1OUT |= BIT0;              // Set P1.0 HIGH

Pero necesito escribir una función que solo tome el Número de puerto, Pin y Valor y establezca los registros anteriores. Algo como esto:

void setVal(int x, int y) {
    PxSEL &= (~BITy);
    PxDIR |= BITy;
    PxOUT |= BITy;
}

Donde x es Puerto e Y es Pin. ¿Hay alguna manera en que pueda implementar tal función? O se ha hecho esto antes? En caso afirmativo, por favor comparte el enlace para el mismo. Estaba pensando en utilizar una tabla de búsqueda y seleccionar el registro a través de la indexación. Pero no estoy seguro de si ese es un buen enfoque. Cualquier ayuda sería apreciada.

Gracias

    

4 respuestas

2

Esto se puede hacer con un conjunto de macros:

#define GPIO_MODE_GPIO(...)  GPIO_MODE_GPIO_SUB(__VA_ARGS__)
#define GPIO_MODE_GPIO_SUB(port, pin) (P##port##SEL &= ~(1<<pin)) // making an assumption about register layout here

#define GPIO_OUT_SET(...)  GPIO_OUT_SET_SUB(__VA_ARGS__)
#define GPIO_OUT_SET_SUB(port, pin) (P##port##OUT &= ~(1<<pin))

//etc...

El operador ## realiza la concatenación de cadenas en el preprocesador. Las macros de dos niveles se utilizan para permitir que se produzca un nivel de expansión de macros entre la primera y la segunda macros, lo que le permite hacer cosas como esta:

#define LED_IO  1,5
GIPO_OUT_SET(LED_IO);

Sin esa indirección adicional, el preprocesador se quejaría de no tener suficientes argumentos para la macro GPIO_OUT_SET .

Este estilo de sistema se ha adaptado bastante bien a cada MCU que he usado hasta ahora, desde AVR hasta ARM, y como es una macro preprocesadora, se compila en el conjunto de instrucciones más pequeño posible.

    
respondido por el ajb
1
  

¿Hay alguna manera de implementar esta función?

Claro, esto se puede hacer. Pero el código ya no será portátil.
Deberá validar el comportamiento cuando cambie la pieza.

Los registros de periféricos GPIO se asignan en el bus en los siguientes rangos:

MODULE       BASE  SIZE
Port P1, P2  0200h 0020h  
Port P3, P4  0220h 0020h  
Port P5, P6  0240h 0020h

Esta es una implementación poco tradicional de TI. Han fusionado puertos pares e impares en un bloque. Por lo general, todos los registros de un bloque GPIO son consecutivos, lo que haría más factible un enfoque aritmético.
Sin embargo, el diseño anterior da los siguientes registros:

P1OUT = 0200h + 02h  
P2OUT = 0200h + 03h  
P3OUT = 0220h + 02h  
P4OUT = 0220h + 03h  
P5OUT = 0240h + 02h  
P6OUT = 0240h + 03h  

Con esos puedes hacer el siguiente código, usando la tabla de arriba:

void setVal(int x, int y) {
    const unsigned char *PxOUT = {0x202, 0x203, 0x222, 0x223, 0x242, 0x243};
    if(y)
        *PxOUT[x] |= (1<<y);
    else
        *PxOUT[x] &= ~(1<<y);
}

Una tabla es el método más rápido disponible. A costa de algunos ROM.
Esto se puede cambiar para permitir el acceso a otros registros también.
Por ejemplo, PxOUT [] -2 accedió al registro PxIN, y +2 es el registro PxDIR.

He tomado mi información de la hoja de datos de msp430fr2153 .
Tabla 6-33 y Tabla 6-41. Es posible que esto no coincida con su parte, marque .

    
respondido por el Jeroen3
1

Mi enfoque en las MCU que ofrecen > 8kB de memoria es empaquetar los GPIO en estructuras:

//
// GPIO Single Pin Descriptor 
//
struct GPIO_SPD      {      const char *    Description;
                            uint8_t         Port;
                            uint16_t        Pin;
                            bool            Initialzied;
};

Luego puede definir un GPIO dentro de su módulo:

struct GPIO_SPD GpioBlinkingLed= {"Simply blinking LED", GPIO_PORT_P1, GPIO_PIN0, false};

Y usa esta estructura dentro de funciones gpio simples similares a las tuyas. Esta estructura, por ejemplo, se puede usar directamente dentro de TI driverlib , de la siguiente manera:

GPIO_setAsOutputPin(GpioBlinkingLed.Port, GpioBlinkingLed.Pin);
GPIO_setOutputHighOnPin(GpioBlinkingLed.Port, GpioBlinkingLed.Pin);
GPIO_toggleOutputOnPin(GpioBlinkingLed.Port, GpioBlinkingLed.Pin);
// etc.

Estas funciones residen en el llamado controlador gpio.c y, por supuesto, se basan en una tabla de búsqueda:

void GPIO_setOutputHighOnPin (uint8_t port, uint16_t pin) 
{
    uint16_t portAddress = GPIO_PORT_ADDRESS_TABLE[port];

    (*((volatile uint16_t *)(portAddress + GPIO_OUT_REG_OFFSET))) |= pin;
}

Lo simplifiqué específicamente, pero obtendrás la idea. GPIO_PORT_ADDRESS_TABLE y GPIO_OUT_REG_OFFSET están predefinidos y los valores se toman de la hoja de datos de MCU. Afortunadamente, TI proporciona MSP430WARE que hace esos últimos bits por usted.

    
respondido por el GAttuso
0

Sería bueno si el código del microcontrolador pudiera usar la sustitución como lo harían los lenguajes de programación típicos de su computadora, pero eso requeriría una capa adicional de complejidad que solo podría hacerse en el microcontrolador, usando la memoria y el espacio de código y el procesamiento.

Puede hacer esto con declaraciones if o case, y su compilador debería poder optimizarlo según sea necesario. Podría tomar el valor de registro que PxSel o lo que realmente significa, y usarlo en su lugar. Todavía requeriría si o el caso o las declaraciones de comparación. Como el fotón menciona en los comentarios, básicamente estarías construyendo una tabla de búsqueda. Afortunadamente, estos son bastante limitados.

Dicho esto, estas funciones se han ejecutado hasta la muerte, la rueda fue reescrita por innumerables desarrolladores varias veces. Una búsqueda en Google para la biblioteca gpio resultaría en una pareja. TI ofrece algunos ejemplos de sus códigos. Y se puede encontrar una copia bastante genérica en Energia , el puerto msp430 (y otros microcontroladores de TI) del marco de código de Arduino. Energia se puede utilizar directamente, solo para la biblioteca gpio Pin, o puede copiarlo, siguiendo la licencia correspondiente.

    
respondido por el Passerby

Lea otras preguntas en las etiquetas