Acceso al pin de E/S individual en MSP430

Estoy transfiriendo un software de Microchip PIC (usando el compilador C de alta tecnología) a TI MSP430, y en el código existente acceden a los pines directamente con algo como:

RA1 = 1;

¿Existe una manera similar de hacer esto con el MSP430, o tengo que escribir en todo el registro de entrada/salida cada vez? Si no es posible, ¿alguien ha encontrado un buen equivalente? Estoy usando Code Composer Studio v5.3 y el compilador que viene con eso.

MSPWare de TI tiene funciones auxiliares para controlar el GPIO (aunque no para todas las subfamilias MSP430).
[nota del moderador: este comentario ha llegado a este hilo como resultado de una fusión.] ¿Qué tiene de malo el capítulo 8 del manual familiar? Tal vez debería proporcionar una pregunta de ejemplo de una "manipulación" muy específica que le gustaría saber cómo hacer. Eso podría contribuir en gran medida a evitar que nos obliguen a escribir y reproducir un capítulo completo para usted.

Respuestas (7)

En el MSP430, el acceso a los pines individuales se suele escribir utilizando operadores definidos y bit a bit :

P2OUT &= ~BIT1;    /* Pin P2.1 = 0 */
P2OUT |= BIT1;     /* Pin P2.1 = 1 */
P2OUT ^= BIT1;     /* Toggle Pin P2.1 */

Asegúrese de incluir el archivo de encabezado adecuado para su chip específico que contenga el puerto y el pin ( BIT#) definido.

Ok, parece que cada vez que veo algo como RA1 = 1;voy a tener que configurar el registro de salida cada vez.
@Dean Más o menos. Las definiciones solo hacen que sea más fácil de leer. Ocasionalmente veo código en línea usando P2OUT.BIT1 = 1;pero no sé si eso funciona o no. En mi experiencia con el MSP430, siempre he usado operaciones bit a bit para acceder a pines individuales. Parece la forma más común de hacer las cosas.
Si está utilizando CCS, debería ser suficiente incluir msp430.h; el compilador detectará automáticamente en qué micro estás.

El siguiente código es una solución para el acceso de pin individual usando Code Composer (con un pequeño ajuste se puede portar a cualquier compilador). El ejemplo es una versión modificada del Ejemplo básico de Code Composer Hacer parpadear el LED. En este ejemplo, en lugar de escribir la sentencia habitual LED=1 para encender el LED, escribirá LED(HI).

//***************************************************************************
//
// MSP432 main.c template - P1.0 port toggle
//
//***************************************************************************

#include "msp.h"

#define LO             0x00
#define HI             0x01

#define BIT_0           0x01
#define BIT_1           0x02
#define BIT_2           0x04
#define BIT_3           0x08
#define BIT_4           0x10
#define BIT_5           0x20
#define BIT_6           0x40
#define BIT_7           0x80

#define LED_BIT          BIT_0

#define LED_PORT         P1OUT

#define LED(x) (x==HI)?(LED_PORT |= LED_BIT):(LED_PORT &= ~LED_BIT)

void main(void)
{
volatile uint32_t i;

WDTCTL = WDTPW | WDTHOLD;           // Stop watchdog timer

// The following code toggles P1.0 port
P1DIR |= BIT0;                      // Configure P1.0 as output

while(1)
{

     //blink LED1
                LED(HI);
                _delay_cycles(100000);
                LED(LO);
                _delay_cycles(100000);
}
}

El foro de discusión de TI tuvo una discusión muy informativa sobre lo mismo.

En resumen, esto se define mediante el msp430.hencabezado genérico utilizado en CCS (que está vinculado al chip de destino específico msp430xxxx.hen la compilación). No tiene soporte para PxOUT.BITyasignaciones de estilo.

io430.h de IAR tiene soporte para eso, pero el consenso es que msp430.hes el mejor encabezado (ya que los msp430xxxx.hencabezados están escritos por empleados de TI, io430.hestán escritos por empleados de IAR)

PxOUT |= BITyEl estilo es la mejor manera de establecer un solo bit. PxOUT &= ~BITyEl estilo es la mejor manera de borrar un solo bit.

Nitpick: PxOUT &= ~BITy aclara un poco. PxOUT |= BITyse pone un poco.

TI lo hace así en uno de sus ejemplos para los compiladores Code Composer Studio (CCS) e IAR:

void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;             // Stop watchdog timer
  P1DIR |= 0x01;                        // Set P1.0 to output direction

  for (;;)
  {
    volatile unsigned int i;

    P1OUT ^= 0x01;                      // Toggle P1.0 using exclusive-OR

    i = 50000;                          // Delay
    do (i--);
    while (i != 0);
  }
}

[nota del moderador: este comentario ha llegado a este hilo como resultado de una fusión.]

[nota del autor: la pregunta original donde publiqué esta respuesta decía que no se pudo encontrar ningún ejemplo de código]

Erm, está bien, me tomó alrededor de 30 segundos encontrar esto:

Sitio web de TI para MSP430F2274

Herramientas y software para MSP430F2274

Código de ejemplo para MSP430F22x4

Y finalmente hay una carpeta llamada Cy en ella encontrará algunos archivos llamados msp430x22x4_p1_0x.cque contienen ejemplos de código sobre cómo usar el Puerto 1 en C. Incluso hay un archivo Léame que le dice qué archivo se usa para qué.

Y para que esta respuesta no sea completamente inútil:

#include <msp430.h>

int main(void)
{
  WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog timer
  P1DIR |= BIT0;                            // Set P1.0 to output direction

  while (1)                                 
  {
    if ((BIT2 & P1IN) == BIT2)
    {
      P1OUT |= BIT0;                        // if P1.2 set, set P1.0
    }
    else
    {
      P1OUT &= ~(BIT0);                       // else reset
    }
  }
}

(En gran medida basado en msp430x22x4_p1_01.cA. Dannenberg / W. Goh, la declaración de derechos de autor completa es demasiado grande para esta respuesta, pero está contenida en el archivo de ejemplo de código vinculado)

Para estar completo (como ejemplo), creo que también debe citar las macros (donde entra en juego la 'magia' del mapa de memoria), por lo que algunos fragmentos del archivo de encabezado. No estoy seguro de si vale la pena el esfuerzo...
@SeanHoulihane bueno, sí, podría, *(uint16_t*)(0x1234U) = 0x20Upero no, el compilador tendrá los archivos de encabezado, por lo que el código debería ser algo como esto.

También quería cambiar el puerto en unidades de bits, así que escribí un código de muestra.
Me alegro si puedes usarlo como referencia.

El código de muestra es para MSP430FR6989.
Vuelva a escribir la dirección si es necesario.
La dirección se puede encontrar en la hoja de datos de cada dispositivo.

typedef carácter sin firmar _BYTE;

unión _BITFIELD {
  _BYTE BYTE;
  estructura {
    _BYTE B7 :1;
    _BYTE B6 :1;
    _BYTE B5 :1;
    _BYTE B4 :1;
    _BYTE B3 :1;
    _BYTE B2 :1;
    _BYTE B1 :1;
    _BYTE B0 :1;
  } POCO;
};

unión un_gpio { /* unión GPIO */
                BYTE de caracteres sin firmar; /* Acceso a bytes */
                estructura { /* Acceso a bits */
                       carácter sin firmar B0 :1;             
                       carácter sin signo B1 :1;             
                       carácter sin firmar B2 :1;             
                       carácter sin firmar B3 :1;             
                       carácter sin firmar B4 :1;             
                       carácter sin signo B5 :1;             
                       carácter sin firmar B6 :1;             
                       carácter sin firmar B7 :1;             
                       } POCO;                      
                };

// Esta es la dirección MSP430FR6989.
#define GPIO1 (*(unión volátil un_gpio *)0x202) /* Dirección IO*/
#define GPIO2 (*(unión volátil un_gpio *)0x203) /* Dirección IO*/
#define GPIO3 (*(unión volátil un_gpio *)0x222) /* Dirección IO*/
#define GPIO4 (*(unión volátil un_gpio *)0x223) /* Dirección IO*/

/**
 * C Principal
 */
int principal (vacío)
{
    WDTCTL = WDTPW | WD TENSIÓN; // detener el temporizador de vigilancia

    // Deshabilite el modo de alta impedancia predeterminado de encendido GPIO para activar
    // ajustes de puerto previamente configurados
    PM5CTL0 &= ~LOCKLPM5;

    //P1SEL &= (~BIT0); // Establecer P1.0 SEL para GPIO
    P1DIR |= BIT0; // Establecer P1.0 como Salida
    P1SALIDA = 0xFF;

    mientras(1)
    {
        //GPIO1.BYTE = 0x01;
        GPIO1.BIT.B0 = 1;
        //GPIO1.BIT.B1 = 1;
        //GPIO1.BIT.B2 = 1;
        //GPIO1.BIT.B3 = 1;
        //GPIO1.BIT.B4 = 1;
        //GPIO1.BIT.B5 = 1;
        //GPIO1.BIT.B6 = 1;
        //GPIO1.BIT.B7 = 1;
        //P1SALIDA = 0x01;

        __delay_cycles(800000);

        //GPIO1.BYTE = 0x00;
        GPIO1.BIT.B0 = 0;
        //GPIO1.BIT.B1 = 0;
        //GPIO1.BIT.B2 = 0;
        //GPIO1.BIT.B3 = 0;
        //GPIO1.BIT.B4 = 0;
        //GPIO1.BIT.B5 = 0;
        //GPIO1.BIT.B6 = 0;
        //GPIO1.BIT.B7 = 0;
        //P1SALIDA = 0x00;

        __delay_cycles(800000);
    }

    devolver 0;
}

El MSP430 puede configurar o borrar bits individuales a través de las instrucciones BIS o BIC (Bit Set).

Así que ciertamente esperaría P2OUT.BIT1 = 1;trabajar en C (al menos en mspgcc; el código Ada equivalente lo hace)

procedure Blinky is
    LED : Boolean renames p1out_bits(0);
begin
    -- Initialise registers etc simplified out
    loop
        LED := True;
        Delay_MS(200);
        LED := False;
        Delay_MS(800);
    end loop;
end Blinky; 
El uso de operaciones de bits debería compilar lo mismo cuando corresponda, incluso si esa sintaxis no está definida.