corni's Link- und Fundstücktonne

blog.cpoth.de
Subscribe

Artikel der Kategorie August, 2012

MSP-EXP430FR5739: ADC10B Sequenz per DMA in Array ablegen

August 17, 2012 Von: corni Kategorie: Programmieren: C, TI Noch keine Kommentare →

Das Beispielprogramm ruft mit 50 Hz den ADC auf welcher eine Serie an Messungen macht (Channel A1, dann A0). Der ADC triggert nach jeder Messung die DMA welche das Messergebnis abholt und in das Array ADC_Result schreibt. Das alles läuft völlig ohne CPU Interaktion.

#include "msp430fr5739.h"

unsigned int ADC_Result[2];

void main(void)
{
	WDTCTL = WDTPW + WDTHOLD;				// Stop WDT

	// Setup clock system
	CSCTL0_H = 0xA5;						// Password
	CSCTL1 |= DCOFSEL0 + DCOFSEL1;          // DCO 8 MHz
	CSCTL2 = SELA_3 + SELS_3 + SELM_3;      // set ACLK = SMCLK = DCO/8

	// Port Setup
	P1SEL0 |= BIT0;                      	// P1.0 is input for ADC
	P1SEL1 |= BIT0;							// Channel A0
	P1SEL1 |= BIT1;							// P1.1 is input for ADC
	P1SEL0 |= BIT1;							// Channel A1

	// Setup der DMA
	DMACTL0 |= DMA0TSEL__ADC10IFG;			// ADC10 interrupt soll die DMA triggern
	__data16_write_addr((unsigned short)&DMA0SA,(unsigned long) &ADC10MEM0);
					// DMA soll das ADC Ergebnis lesen...
	__data16_write_addr((unsigned short)&DMA0DA,(unsigned long) &ADC_Result[0]);
					// ...und ins array ADC_Result[] schreiben
	DMA0SZ = 2;								// One word per transfer
	DMA0CTL |= DMADT_4;						// Repeated single transfer
	DMA0CTL &= ~DMADSTBYTE;					// DMA destination is a word
	DMA0CTL &= ~DMASRCBYTE;					// DMA source is a word
	DMA0CTL |= DMASRCINCR_0;				// Source address is unchanged (immer gleiches Register)
	DMA0CTL |= DMADSTINCR_3;				// Destination address is incremented (nächstes array element)
	DMA0CTL &= ~DMALEVEL;					// Trigger on low level (otherwise DMA is too fast)
	DMA0CTL |= DMAIE;						// Enable Interrupts
	DMA0CTL |= DMAEN;						// Enable DMA

	// Setup Timer
	TA0CCR0 = 20000 - 1;					// PWM Period 50 Hz
	TA0CCTL1 = OUTMOD_7;					// CCR1 reset/set
	TA0CCR1 = 2000;							// CCR1 PWM duty cycle 10 %
	TA0CTL = TASSEL_2 + MC_1 + TACLR;		// SMCLK, up mode, clear TAR

	// Setup ADC
	ADC10CTL0 &= ~ADC10ENC;
	ADC10CTL1 |= ADC10CONSEQ_3;				// Repeat-Sequence-of-Channels Mode
	ADC10CTL1 |= ADC10SHS_1;				// Set PWM as trigger source
	ADC10CTL1 &= ~ADC10SHP;					// Bypass Sample timer
	ADC10CTL2 |= ADC10RES;                  // 10-bit conversion results
	ADC10MCTL0 |= ADC10INCH_1;				// Start Sequence with Channel A1
	ADC10CTL0 |= ADC10ON;					// ADC on
	ADC10CTL0 |= ADC10ENC;					// Enable ADC conversation

	_BIS_SR(GIE);							// General interrupt enable

	while(1) __bic_SR_register(CPUOFF);		// CPU off
}


#pragma vector=DMA_VECTOR
__interrupt void DMA0_ISR (void)
{
	switch(__even_in_range(DMAIV,16))
	{
		case  0: break;						// No interrupt
		case  2:
			// ADC and DMA are ready, values are now stored in Array ADC_Result
			__no_operation();				// Set breakpoint here
			break;							// DMA0IFG
		case  4: break;						// DMA1IFG
		case  6: break;						// DMA2IFG
		case  8: break;						// Reserved
		case 10: break;						// Reserved
		case 12: break;						// Reserved
		case 14: break;						// Reserved
		case 16: break;						// Reserved
		default: break;
	}
}

Enter MSP430F5xxx LPMx.5

August 13, 2012 Von: corni Kategorie: Programmieren: C, TI Noch keine Kommentare →

Das geht in C so:

	PMMCTL0_H = PMMPW_H;					// Enter PMM password
	PMMCTL0_L |= PMMREGOFF;					// Enter LPMx.5 when PMMREGOFF is set

	__bis_SR_register([LPM3;LPM4]_bits);	// Enter LPM

MSP-EXP430FR5739: ADC10B Sequenz mit PWM triggern

August 08, 2012 Von: corni Kategorie: Programmieren: C, TI Noch keine Kommentare →

Der ADC10B des MSP430 kann auch automatisch mehrere Kanäle nacheinander messen, ohne dass manuell hin und her geschaltet werden muss.
Das folgende Programm misst zunächst Kanal A1 und dann A0. Der ADC fängt immer beim höchsten in ADC10MCTL0 eingestellen Kanal an und zählt dann herunter. Nach jeder Messung wird in diesem Programm ein Interrupt ausgelöst und der gerade gemessene Wert kann ausgelesen werden.

#include "msp430fr5739.h"

unsigned int ADC_Result;

void main(void)
{
	WDTCTL = WDTPW + WDTHOLD;				// Stop WDT

	// Setup clock system
	CSCTL0_H = 0xA5;						// Password
	CSCTL1 |= DCOFSEL0 + DCOFSEL1;          // DCO 8 MHz
	CSCTL2 = SELA_3 + SELS_3 + SELM_3;      // set ACLK = SMCLK = DCO/8

	// Port Setup
	P1SEL0 |= BIT0;                      	// P1.0 is input for ADC
	P1SEL1 |= BIT0;							// Channel A0
	P1SEL1 |= BIT1;							// P1.1 is input for ADC
	P1SEL0 |= BIT1;							// Channel A1

	// Setup Timer
	TA0CCR0 = 20000 - 1;						// PWM Period 50 Hz
	TA0CCTL1 = OUTMOD_7;						// CCR1 reset/set
	TA0CCR1 = 2000;								// CCR1 PWM duty cycle 10 %
	TA0CTL = TASSEL_2 + MC_1 + TACLR;			// SMCLK, up mode, clear TAR

	// Setup ADC
	ADC10CTL0 &= ~ADC10ENC;
	ADC10CTL0 |= ADC10SHT_2 + ADC10ON;      // ADC10ON, S&H=16 ADC clks
	ADC10CTL1 |= ADC10CONSEQ_3;				// Repeat-Sequence-of-Channels Mode
	ADC10CTL1 |= ADC10SHS_1;				// Set PWM as trigger source
	ADC10CTL1 &= ~ADC10SHP;					// Bypass Sample timer
	ADC10CTL2 |= ADC10RES;                  // 10-bit conversion results
	ADC10MCTL0 |= ADC10INCH_1;				// Start Sequence with Channel A1
	ADC10IE |= ADC10IE0;                    // Enable ADC conv complete interrupt
	ADC10CTL0 |= ADC10ENC;					// Enable ADC conversation

	_BIS_SR(GIE);

	while(1) __bic_SR_register(CPUOFF);
}

#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR(void)
{
	__no_operation();
  switch(__even_in_range(ADC10IV,12))
  {
    case  0: break;                          // No interrupt
    case  2: break;                          // conversion result overflow
    case  4: break;                          // conversion time overflow
    case  6: break;                          // ADC10HI
    case  8: break;                          // ADC10LO
    case 10: break;                          // ADC10IN
    case 12:
    	ADC_Result = ADC10MEM0;
    	__no_operation();
        __bic_SR_register_on_exit(CPUOFF);
        break;

    default: break;
  }
}

MSP-EXP430FR5739: ADC10B mit PWM triggern

August 06, 2012 Von: corni Kategorie: Programmieren: C, TI Noch keine Kommentare →

Im folgenden Beispiel wird mit dem Timer A0 eine PWM (50 Hz, 10 % duty cycle) erzeugt welche ohne CPU Interaktion den ADC 10B des MSP430FR5739 triggert und eine Messung auslöst. Gemessen wird die Spannung an Port 1.1. Ist der ADC fertig wird ein Interrupt ausgelöst.
Nur während die ISR läuft wacht die CPU kurz auf.

#include "msp430fr5739.h"

unsigned int ADC_Result;

void main(void)
{
	WDTCTL = WDTPW + WDTHOLD;				// Stop WDT

	// Setup clock system
	CSCTL0_H = 0xA5;						// Password
	CSCTL1 |= DCOFSEL0 + DCOFSEL1;          // DCO 8 MHz
	CSCTL2 = SELA_3 + SELS_3 + SELM_3;      // set ACLK = SMCLK = DCO/8

	// Port Setup
	P1DIR |= BIT0;                          // Set P1.0 to output direction
	P1SEL0 |= BIT0;                      	// P1.0 is output for PWM for debugging
	P1SEL1 |= BIT1;							// P1.1 is input for ADC
	P1SEL0 |= BIT1;							// P1.1 is input for ADC

	// Setup Timer
	TA0CCR0 = 20000 - 1;						// PWM Period 50 Hz
	TA0CCTL1 = OUTMOD_7;						// CCR1 reset/set
	TA0CCR1 = 2000;								// CCR1 PWM duty cycle 10 %
	TA0CTL = TASSEL_2 + MC_1 + TACLR;			// SMCLK, up mode, clear TAR

	// Setup ADC
	ADC10CTL0 &= ~ADC10ENC;
	ADC10CTL0 |= ADC10SHT_2 + ADC10ON;      // ADC10ON, S&H=16 ADC clks
	ADC10CTL1 |= ADC10CONSEQ_2;				// Single-channel repeat
	ADC10CTL1 |= ADC10SHS_1;				// Set PWM as trigger source
	ADC10CTL1 &= ~ADC10SHP;					// Bypass Sample timer
	ADC10CTL2 |= ADC10RES;                  // 10-bit conversion results
	ADC10MCTL0 |= ADC10INCH_1;              // A1 ADC input select; Vref=AVCC
	ADC10IE |= ADC10IE0;                    // Enable ADC conv complete interrupt
	ADC10CTL0 |= ADC10ENC;					// Enable ADC conversation

	_BIS_SR(GIE);

	while(1) __bic_SR_register(CPUOFF);
}

#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR(void)
{
	__no_operation();
  switch(__even_in_range(ADC10IV,12))
  {
    case  0: break;                          // No interrupt
    case  2: break;                          // conversion result overflow
    case  4: break;                          // conversion time overflow
    case  6: break;                          // ADC10HI
    case  8: break;                          // ADC10LO
    case 10: break;                          // ADC10IN
    case 12:
    	ADC_Result = ADC10MEM0;
    	__no_operation();
        __bic_SR_register_on_exit(CPUOFF);
        break;

    default: break;
  }
}

HyperTerminal for Windows 7

August 01, 2012 Von: corni Kategorie: Microsoft Noch keine Kommentare →

…leider hat Microsoft es entfernt.
Wer es trotzdem braucht findet es hier.

MSP430 LaunchPad SPI Example

August 01, 2012 Von: corni Kategorie: Programmieren: C, TI Noch keine Kommentare →

Das folgende Programm verschickt auf Tasterdruck (S2) ein byte (0x22) per SPI.

// P1.5 = SCLK
// P1.6 = DOUT
// P1.7 = DIN

#include <msp430.h>

void main(void)
{

	WDTCTL = WDTPW + WDTHOLD;             // Stop watchdog timer

	// Port 1.3: Switch Input
	P1DIR &= ~BIT3;						// P1.3 = input
	P1REN |= BIT3;						// Pullup/down resistor enabled
	P1OUT |= BIT3;						// Pin is pulled enabled
	P1IE |= BIT3;						// Enable interrupts from switch
	P1IES |= BIT3;						// rising edge

	// Setup USI -> SPI Master
	USICTL0 |= USIPE7 +  USIPE6 + USIPE5 + USIMST + USIOE;	// Port, SPI master
	USICTL1 |= USIIE;					// Counter interrupt, flag remains set
	USICTL1 |= USICKPH;					// Data is captured on the first SCLK edge and changed on the following edge
	USICKCTL = USIDIV_4 + USISSEL_2;	// /16 SMCLK
	USICTL1 &= ~USIIFG;					// reset IRQ flag
	USICTL0 &= ~USISWRST;				// USI released for operation

	_BIS_SR(GIE);
	while(1);
}

#pragma vector=USI_VECTOR
__interrupt void universal_serial_interface(void)
{
	USICTL1 &= ~USIIFG;					// reset IRQ flag
}

#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void)
{
	P1IE &= ~BIT3;						// Disable interrupts from switch

	USISRL = 0x22;						// write data to send into fifo
	USICNT = 8;							// reload counter

	P1IFG &= ~BIT3; 					// clear Interrupt Flag
	P1IE |= BIT3;						// Enable interrupts from switch
}

Mit dem folgenden Programm können die Daten auf einem zweiten LaunchPad empfangen werden:

#include <msp430.h>

void main(void)
{
	int received_data[1];
	WDTCTL = WDTPW + WDTHOLD;             // Stop watchdog timer

	// Setup USI -> SPI Slave
	USICTL0 |= USIPE7 +  USIPE6 + USIPE5 + USIOE;	// Port setup
	USICNT &= ~USI16B;					// only 8 bit mode
	USICTL0 &= ~USIMST;					//  SPI slave
	USICTL1 |= USIIE;					// Counter interrupt, flag remains set
	USICTL1 |= USICKPH;					// Data is captured on the first SCLK edge and changed on the following edge
	USICKCTL = USIDIV_4 + USISSEL_2;	// /16 SMCLK
	USICTL1 &= ~USIIFG;					// reset IRQ flag
	USICTL0 &= ~USISWRST;				// USI released for operation
	received_data[0] = USISRH;
	received_data[0] = USISRL;			// Empty USISRL
	//USISRL = 0x22;
	USICNT = 7;                           // init-load counter

	_BIS_SR(GIE);
	while(1);

}

#pragma vector=USI_VECTOR
__interrupt void universal_serial_interface(void)
{
	int received_data[1];
	received_data[0] = USISRH;
	received_data[0] = USISRL;

	USICNT = 7;
	USICTL1 &= ~USIIFG;					// reset IRQ flag
}