CVS: examples/fet_spi_irq hardware.h,NONE,1.1 irqspi.S,NONE,1.1 irqspi.h,NONE,1.1 main.c,NONE,1.1 makefile,NONE,1.1 spicontrol_gui.py,NONE,1.1 spicontrol_gui.wxg,NONE,1.1 spicontroller.py,NONE,1.1

Chris Liechti <[email protected]>
Newsgroups gmane.comp.hardware.texas-instruments.msp430.gcc.cvs
Message-ID <[email protected]>
Update of /cvsroot/mspgcc/examples/fet_spi_irq
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5510/examples/fet_spi_irq

Added Files:
	hardware.h irqspi.S irqspi.h main.c makefile spicontrol_gui.py 
	spicontrol_gui.wxg spicontroller.py 
Log Message:
Import of software SPI over the JTAG lines example, including demo Python apps for the PC. This code runs on the F11xx FET kit or a F1121 with just the JTAG interface.

--- NEW FILE: hardware.h ---
#ifndef HARDWARE_H
#define HARDWARE_H
/*
Compatible with the F11xx FET KIT from TI.
The JTAG interface is used as level converter for a SPI master controlled
by the PC. Therefore the SPI pins were choosen that way.

                MSP430F1121
             -----------------
         /|\|              XIN|-
          | |                 |
          --|RST          XOUT|-
            |                 |
      NC <--|P2.0         P1.0|--> LED
      NC <--|P2.1         P1.1|--> FREQ_OUT
      NC <--|P2.2         P1.2|--> PWM_OUT1
      NC <--|P2.3         P1.3|--> PWM_OUT2
      NC <--|P2.4         P1.4|--> TCK      CLK   \
      NC <--|P2.5         P1.5|--> TMS      /CS   | SPI lines
            |             P1.6|--> TDI      SIMO  |
            |             P1.7|--> TDO      SOMI  /
            |                 |
             -----------------

The timer is set up as PWM. The base frequency (FREQ_OUT) and the two PWM
signals (PWM_OUTx) are output on the pins P1.1 to P1.3. The FET kit also
has a LED on P1.0 which is high active.

(C) 2004 Chris Liechti <[email protected]>
this is distributed under a free software license, see license.txt

http://mspgcc.sf.net
*/

#include <io.h>
#include <signal.h>

//PINS
//--- PORT1 ---
#define LED             BIT0
#define FREQ_OUT        BIT1
#define PWM_OUT1        BIT2
#define PWM_OUT2        BIT3
#define TCK             BIT4
#define TMS             BIT5
#define TDI             BIT6
#define TDO             BIT7

#define P1OUT_INIT      TDO
#define P1SEL_INIT      FREQ_OUT|PWM_OUT1|PWM_OUT2
#define P1DIR_INIT      FREQ_OUT|PWM_OUT1|PWM_OUT2|TDO|LED

#define P1IE_INIT       0
#define P1IES_INIT      0

#define LED_OFF()       (P1OUT &= ~LED)
#define LED_ON()        (P1OUT |=  LED)

//--- PORT2 ---
#define NC20            BIT0
#define NC21            BIT1
#define NC22            BIT2
#define NC23            BIT3
#define NC24            BIT4
#define NC25            BIT5

#define P2OUT_INIT      0
#define P2SEL_INIT      0
#define P2DIR_INIT      NC20|NC21|NC22|NC23|NC24|NC25

#define CAPD_INIT       0

#define P2IE_INIT       0
#define P2IES_INIT      0

////
#define IE1_INIT        0
#define IE2_INIT        0
#define ME1_INIT        0
#define ME2_INIT        0


#define WDTCTL_INIT     WDTPW|WDTHOLD

#define BCSCTL1_INIT    XT2OFF|RSEL2|RSEL1|RSEL0
#define BCSCTL2_INIT    0
#define DCOCTL_INIT     0xff

//~ #define TACTL_INIT      TASSEL_ACLK|TACLR
#define TACTL_INIT      TASSEL_SMCLK|TACLR

#endif //HARDWARE_H

--- NEW FILE: irqspi.S ---
/**
Software SPI slave in port interrupt.

This code uses the P1 pins that are shared with the JTAG interface on
the F11x and F12x parts.

The port interrupts are used, no other P1 interrupts should be used.
Or at least their handling has to be added in this code.

The globals spi_data_out and spi_data_in are used as data registers.
When a byte is complete IRQ_SPI_rx is called, which must be an interrupt
function (does not need to be attached to a real interrupt vector, use
NOVECTOR instead). That function can read the received byte in spi_data_in
and it can set up the next outgoing character.

The data is copied to a separate shift register on byte start/stop, so that
spi_data_out and spi_data_in can be read or written at any time. But it's
recomened to read/write them in IRQ_SPI_rx only.

spi_data_out is set to 0xff after the data has been copied to the shift
register. This means that a 0xff is sent if no data is set up by the users
code.

Pins:
    P1.5 TMS  is used as low active chip select (/CS) a neg edge on
    this pin resets the SPI statemachine.

    P1.4 TCK  is used as SPI CLK input
    P1.6 TDI  is the data input SIMO
    P1.7 TDO  is the data output SOMI

NOTE: Unlike a real SPI device, the SPI pins are currently not switched
      to 3-state (input) when the chip select (/CS) is high.

NOTE: Due to the nature of a software implementation, it can not handle
      SPI clocks higher than a few kHz, depending on the CPU speed.
      It worked fine up to 43kHz with the DCO/MCLK at full speed (5 MHz).


(C) 2004 Chris Liechti <[email protected]>
this is distributed under a free software license, see license.txt

http://mspgcc.sf.net
*/

#include "hardware.h"

;variables
.data
    .global spi_data_out
    .global spi_data_in
    .comm   spi_data_out,       1, 1            ;char var, not aligned
    .comm   spi_data_in,        1, 1            ;char var, not aligned

    .comm   spi_shift,          1, 1            ;char var, not aligned
    .comm   spi_state,          2, 2            ;short var, aligned
; use regs for faster code. must be used with "-ffixed-regs=..." !
//~ #define spi_shift r6
//~ #define spi_state r7

.text

/*
This one initializes the P1 settings used for the software SPI.
it also sets up the internal variables.
*/

.global spi_init
spi_init:
                mov.b   #0xff, spi_data_out
                mov.b   #0xff, spi_data_in
                clr     spi_state               ; reset state
                bis.b   #TDO, &P1OUT            ; set output
                mov.b   #(TCK|TMS), &P1IES      ; switch to neg edge detect
                mov.b   #(TCK|TMS), &P1IE       ; enable interrupts on CLK and CS
                ret


/*
Port interrupt handler. Shift one byte out, read one byte in, in SPI
slave fashion. The user must supply an interrupt function named IRQ_SPI_rx
which is called when a byte is complete.

It's implemented with a jump table and as fast as possible, however it's
nowhere as fast as a hardware SPI (see note in the comment above)...
*/
interrupt (PORT1_VECTOR)
.LSPI_shift:
                bit.b   #TCK, &P1IFG            ; clock edge?
                jz      .LSPI_CS                ; no -> jump
                bic.b   #TCK, &P1IFG            ; clear flag
                xor.b   #TCK, &P1IES            ; switch to neg/pos edge detect
                add     spi_state, r0           ; jump table
                jmp     .LSPI_bit_low_first     ; Do7
                jmp     .LSPI_bit_high          ; Di7
                jmp     .LSPI_bit_low           ; Do6
                jmp     .LSPI_bit_high          ; Di6
                jmp     .LSPI_bit_low           ; Do5
                jmp     .LSPI_bit_high          ; Di5
                jmp     .LSPI_bit_low           ; Do4
                jmp     .LSPI_bit_high          ; Di4
                jmp     .LSPI_bit_low           ; Do3
                jmp     .LSPI_bit_high          ; Di3
                jmp     .LSPI_bit_low           ; Do2
                jmp     .LSPI_bit_high          ; Di2
                jmp     .LSPI_bit_low           ; Do1
                jmp     .LSPI_bit_high          ; Di1
                jmp     .LSPI_bit_low           ; Do0
                //jmp   .LSPI_bit_high_last     ; Di0  code follows directly
.LSPI_bit_high_last:
                bit.b   #TDI, &P1IN             ; sample input
                rlc.b   spi_shift               ; and store it in the answer byte
                clr     spi_state               ; reset state
                mov.b   spi_shift, spi_data_in  ; copy incomming data
                eint
                br      #IRQ_SPI_rx             ; call user interrupt function on complete character

.LSPI_bit_high:
                bit.b   #TDI, &P1IN             ; sample input
                rlc.b   spi_shift               ; and store it in the answer byte
                incd    spi_state
                reti

.LSPI_bit_low_first:
                mov.b   spi_data_out, spi_shift ; copy outgoing data
                mov.b   #0xff, spi_data_out     ; set to idle so that the data is not repeated
.LSPI_bit_low:
                incd    spi_state
                tst.b   spi_shift               ; check msb
                jn      .Ltx_one
.Ltx_zero:      bic.b   #TDO, &P1OUT
                reti
.Ltx_one:       bis.b   #TDO, &P1OUT
                reti


.LSPI_CS:
                bit.b   #TMS, &P1IFG            ; was /CS activated?
                jz      .L_reti                 ; no -> jump
                bic.b   #TMS, &P1IFG            ; clear flag
                call    #spi_init               ; init interface on CS->LOW
.L_reti:        reti



--- NEW FILE: irqspi.h ---
#ifndef IRQSPI_H

/*
Software SPI, public functions and variables.
See irqspi.S for a detailed description.

(C) 2004 Chris Liechti <[email protected]>
this is distributed under a free software license, see license.txt

http://mspgcc.sf.net
*/

#ifndef _GNU_ASSEMBLER_

void spi_init(void);

extern unsigned char spi_data_out;      ///< outgoing data
extern unsigned char spi_data_in;       ///< incomming data

#endif //_GNU_ASSEMBLER_

#endif //IRQSPI_H

--- NEW FILE: main.c ---
/**
see README.txt for details.

Software SPI demo.

SPI protocol description. The SPI RX interrupt function implements
the protocol described below. Received commands are delegated to the
foreground for execution. This allows for long running commands (like
sampling ADC etc.)

Protocol control characters:
    0xff         IDLE
    0xfe         DONE, command complete
    0xfd         BUSY, command is beeing received or executed
    0xfc..0xf2   [reserved]
    0xf1         NACK, answer complete, failure
    0xf0         ACK, answer complete, ok

These characters must not be used in the data fields.

Basic command transfer:
    master->slave: cmd   [arg bytes] DONE  IDLE.....................
    slave->master: IDLE  BUSY............  [BUSY] [ans bytes] (N)ACK

The master starts with the command followed by data (optionaly).
the slave is sending 0xfd (BUSY). 0xfe (DONE) finishes the command and
initiates execution.
The slave can continue with 0xfd (BUSY) while processing the command.
The answer is sent when ready, if there is any, and the command
is finished by 0xf0 (ACK) or 0xf1 (NACK), indicating success or failure.

As some characters are reserved and must not be used in the data, it's
not possible to transmit raw binary data. These special characters have
to escaped or the entire data has to be encoded. This example expects
binary data as hex encoded string.

e.g. "6466"(hex) -> "@B"(binary)

(C) 2004 Chris Liechti <[email protected]>
this is distributed under a free software license, see license.txt

http://mspgcc.sf.net
*/
#include "hardware.h"
#include "irqspi.h"
#include <string.h>


char spi_buffer[20];            ///< send receive buffer for commands
volatile int spi_answer_length; ///< length of the answer in spi_buffer
volatile int spi_answer_byte;   ///< answer code: SPI_X_ACK or SPI_X_NACK

//commands
volatile enum {
    CMD_IDLE,           //mandatory, used in the statemachine in IRQ_SPI_rx
    CMD_SETLED,         //LED control
    CMD_DELAY,          //delay test
    CMD_SET_FREQ,       //PWM base freq
    CMD_SET_PWM,        //set both PWM duty cycles
} spi_cmd;                      ///< received command code

//Protocol control characters
#define SPI_X_IDLE      0xff
#define SPI_X_DONE      0xfe
#define SPI_X_BUSY      0xfd
#define SPI_X_NACK      0xf1
#define SPI_X_ACK       0xf0

/** just a simple busy wait delay */
void delay(unsigned short d) {
    for (; d; d--) {
        nop();
    }
}

/** Convert hex digit to a number.  */
static unsigned int fromhex(char a) {
    if ((a >= '0') && (a <= '9')) {
        return a - '0';
    } else if ((a >= 'a') && (a <= 'f')) {
        return (a - 'a') + 10;
    } else {
        return 0;//invalid hex digit
    }
}

/** Convert number to a hex digit.  */
static int tohex(unsigned int nib) {
    if (nib < 10) {
        return '0' + nib;
    } else {
        return 'a' + nib - 10;
    }
}

/** decode hex pairs of letters to binary */
unsigned int unhexlify(const char *in, char *out, unsigned int max_outlen) {
    unsigned int length = 0;
    while (*in && (length < max_outlen)) {
        *out = fromhex(*in++) << 4;
        if (*in == 0) break;    //odd number of input characters
        *out |= fromhex(*in++);
        out++;
        length++;
    }
    return length;
}

/** encode binary data to hex digit pairs*/
unsigned int hexlify(const char *in, unsigned int in_length, char *out, unsigned int max_outlen) {
    unsigned int length = 0;
    while ((length/2 < in_length) && (length < (max_outlen - 3))) {
        *out++ = tohex((*in >> 4) & 0xf);
        *out++ = tohex((*in >> 0) & 0xf);
        in++;
        length+=2;
    }
    *out = '\0';
    return length;
}


interrupt(NOVECTOR) IRQ_SPI_rx(void) {
    static enum {SPI_IDLE, SPI_GETCMD, SPI_PROCESSING, SPI_ANSWER} mode;
    static int pos;
    
    //statemachine
    switch (mode) {
        case SPI_IDLE:
            //wait for a command
            spi_data_out = SPI_X_IDLE;
            if (spi_data_in != SPI_X_IDLE) {
                spi_data_out = SPI_X_BUSY;
                spi_cmd = spi_data_in;
                mode = SPI_GETCMD;
            }
            break;
            
        case SPI_GETCMD:
            //read command args, wait for DONE tag
            spi_data_out = SPI_X_BUSY;
            if (spi_data_in == SPI_X_DONE) {
                pos = 0;
                if (spi_cmd) {
                    //any command except CMD_IDLE
                    spi_answer_byte = 0;
                    _BIC_SR_IRQ(LPM4_bits); //wakeup foreground to process command
                    mode = SPI_PROCESSING;
                } else {
                    //CMD_IDLE
                    spi_answer_length = 0;
                    mode = SPI_ANSWER;
                    spi_answer_byte = SPI_X_ACK;
                }
            } else {
                if (pos < sizeof(spi_buffer)) {
                    spi_buffer[pos++] = spi_data_in;
                }
            }
            break;
        
        case SPI_PROCESSING:
            //while the command is processed, send IDLE
            //if spi_answer_byte != 0 signals that the processing is done
            spi_data_out = SPI_X_BUSY;
            if (spi_answer_byte) {
                mode = SPI_ANSWER;
            }
            break;
        
        case SPI_ANSWER:
            //send answer: first send buffer if spi_answer_length is not
            //zero, then send the spi_answer_byte to finish the command
            if (pos < spi_answer_length) {
                spi_data_out = spi_buffer[pos++];
            } else {
                pos = 0;
                spi_data_out = spi_answer_byte;
                mode = SPI_IDLE;
            }
            break;
    }
}


/**
Main function with hardware init and command handler.
*/
int main(void) {
    char buffer[10];
    
    WDTCTL = WDTCTL_INIT;               //Init watchdog timer

    P1OUT  = P1OUT_INIT;                //Init output data of port1
    P1SEL  = P1SEL_INIT;                //Select port or module -function on port1
    P1DIR  = P1DIR_INIT;                //Init port direction register of port1
    P1IES  = P1IES_INIT;                //init port interrupts
    P1IE   = P1IE_INIT;

    P2OUT  = P2OUT_INIT;                //Init output data of port2
    P2SEL  = P2SEL_INIT;                //Select port or module -function on port2
    P2DIR  = P2DIR_INIT;                //Init port direction register of port2
    P2IES  = P2IES_INIT;                //init port interrupts
    P2IE   = P2IE_INIT;
    CAPD   = CAPD_INIT;                 //Init input buffers on port2 pins

    BCSCTL1 = BCSCTL1_INIT;
    BCSCTL2 = BCSCTL2_INIT;
    DCOCTL  = DCOCTL_INIT;

    TACTL = TACTL_INIT;
    CCR0  = 0xffff;
    CCR1  = 0x8000;
    CCR2  = 0x8000;
    CCTL0 = OUTMOD_TOGGLE;
    CCTL1 = OUTMOD_RESET_SET;
    CCTL2 = OUTMOD_RESET_SET;
    TACTL |= MC_UPTO_CCR0;
    
    spi_init();                         //initialize software SPI
    eint();                             //enable interrupts

    while (1) {
        //wait in lowpower mode for commands
        LPM0;
        
        //decode received data from hex to binary
        unhexlify(spi_buffer, buffer, sizeof(buffer));
        
        //execute command
        switch (spi_cmd) {
            case CMD_SETLED:
                //switching the LED on or off
                if (spi_buffer[0]) LED_ON(); else LED_OFF();
                strcpy(spi_buffer, "led ok");
                spi_answer_length = 6;
                spi_answer_byte = SPI_X_ACK;
                break;
            
            case CMD_SET_FREQ:
                //set the base frequency
                CCR0 = *((unsigned short *)buffer);
                spi_answer_length = 0;
                spi_answer_byte = SPI_X_ACK;
                break;
            
            case CMD_SET_PWM:
                //set the PWM outputs
                CCR1 = ((unsigned short *)buffer)[0];
                CCR2 = ((unsigned short *)buffer)[1];
                spi_answer_length = 0;
                spi_answer_byte = SPI_X_ACK;
                break;

            case CMD_DELAY:
                //test for a command that takes a while to execute
                delay(0xffff);
                delay(0xffff);
                strcpy(spi_buffer, "dly ok");
                spi_answer_length = 6;
                spi_answer_byte = SPI_X_ACK;
                break;
            
            default:
                //unknown command
                strcpy(spi_buffer, "unk cmd");
                spi_answer_length = 7;
                spi_answer_byte = SPI_X_NACK;
                break;
        }
    }
}


--- NEW FILE: makefile ---
# makfile configuration
NAME            = fet_spi
CSOURCES        = main.c
ASOURCES        = irqspi.S
CPU             = msp430x1121

ASFLAGS         = -mmcu=${CPU} -D_GNU_ASSEMBLER_
CFLAGS          = -mmcu=${CPU} -O2 -Wall -g

#switch the compiler (for the internal make rules)
CC              = msp430-gcc
AS              = msp430-gcc

OBJECTS         = ${CSOURCES:.c=.o} ${ASOURCES:.S=.o}

.PHONY: all FORCE clean download download-jtag download-bsl dist

#all should be the first target. it's built when make is run without args
#~ all: ${NAME}.elf ${NAME}.a43 ${NAME}.lst
all: ${NAME}.elf ${NAME}.lst

#confgigure the next line if you want to use the serial download
download: download-jtag
#download: download-bsl

#additional rules for files
${NAME}.elf: ${OBJECTS}
	${CC} -mmcu=${CPU} -o $@ ${OBJECTS}

${NAME}.a43: ${NAME}.elf
	msp430-objcopy -O ihex $^ $@

${NAME}.lst: ${NAME}.elf
	msp430-objdump -dSt $^ >$@
	echo >>$@ " "
	echo >>$@ "----- RAM/Flash Usage -----"
	msp430-size $^ $(OBJECTS) >>$@

download-jtag: all
	msp430-jtag -e ${NAME}.elf

download-bsl: all
	msp430-bsl -e ${NAME}.elf

clean:
	rm -f ${NAME} ${NAME}.a43 ${NAME}.lst ${OBJECTS} dependencies.d

dependencies.d:
	$(CC) -MM ${CFLAGS} ${CSOURCES} > dependencies.d
	$(CC) -MM ${ASFLAGS} ${ASOURCES} >> dependencies.d

#backup archive
dist:
	tar czf dist.tgz *.c *.h *.txt makefile

#dummy target as dependecy if something has to be build everytime
FORCE:

#project dependencies
-include dependencies.d

--- NEW FILE: spicontrol_gui.py ---
#!/usr/bin/env python
# Demonstration GUI for the SPI protocol implementation.
# Featuring sliders for the PWM control and a checkbox for the LED.
#
# (C) 2004 Chris Liechti <[email protected]>
# this is distributed under a free software license, see license.txt
#
# http://mspgcc.sf.net
#
# Requires Python 2.3+ and the msp430 modules, wxPython 2.4+
#
# $Id: spicontrol_gui.py,v 1.1 2004/07/16 01:19:55 cliechti Exp $

import wx
import spicontroller

class MainFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        # begin wxGlade: MainFrame.__init__
        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.panel_1 = wx.Panel(self, -1)
        self.label_1 = wx.StaticText(self.panel_1, -1, "Frequency")
        self.slider_1 = wx.Slider(self.panel_1, -1, 50, 1, 100, style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS|wx.SL_LABELS)
        self.label_2 = wx.StaticText(self.panel_1, -1, "PWM 1")
        self.slider_2 = wx.Slider(self.panel_1, -1, 10, 0, 100, style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS|wx.SL_LABELS)
        self.label_3 = wx.StaticText(self.panel_1, -1, "PWM 2")
        self.slider_3 = wx.Slider(self.panel_1, -1, 20, 0, 100, style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS|wx.SL_LABELS)
        self.checkbox_led = wx.CheckBox(self.panel_1, -1, "LED")

        self.__set_properties()
        self.__do_layout()
        # end wxGlade
        self.__attach_events()
        #init port and hardware
        spicontroller.init()
        #initialize with defaults, so that sliders/LED match with the displayed values
        self.OnSlideFreq()
        self.OnSlidePWM()
        self.OnLED()

    def __set_properties(self):
        # begin wxGlade: MainFrame.__set_properties
        self.SetTitle("SPI Control")
        self.slider_1.SetSize((277, -1))
        self.slider_2.SetSize((277, -1))
        self.slider_3.SetSize((277, -1))
        # end wxGlade

    def __do_layout(self):
        # begin wxGlade: MainFrame.__do_layout
        sizer_1 = wx.BoxSizer(wx.VERTICAL)
        sizer_2 = wx.BoxSizer(wx.VERTICAL)
        grid_sizer_1 = wx.FlexGridSizer(3, 2, 4, 0)
        grid_sizer_1.Add(self.label_1, 0, wx.ALL, 4)
        grid_sizer_1.Add(self.slider_1, 1, 0, 0)
        grid_sizer_1.Add(self.label_2, 0, wx.ALL, 4)
        grid_sizer_1.Add(self.slider_2, 1, 0, 0)
        grid_sizer_1.Add(self.label_3, 0, wx.ALL, 4)
        grid_sizer_1.Add(self.slider_3, 1, 0, 0)
        sizer_2.Add(grid_sizer_1, 0, wx.ALL, 4)
        sizer_2.Add(self.checkbox_led, 0, wx.ALL, 4)
        self.panel_1.SetAutoLayout(1)
        self.panel_1.SetSizer(sizer_2)
        sizer_2.Fit(self.panel_1)
        sizer_2.SetSizeHints(self.panel_1)
        sizer_1.Add(self.panel_1, 1, wx.EXPAND, 0)
        self.SetAutoLayout(1)
        self.SetSizer(sizer_1)
        sizer_1.Fit(self)
        sizer_1.SetSizeHints(self)
        self.Layout()
        # end wxGlade

    def __attach_events(self):
        #~ wx.EVT_CLOSE(self, self.onWindowClose)
        wx.EVT_SLIDER(self, self.slider_1.GetId(), self.OnSlideFreq)
        wx.EVT_SLIDER(self, self.slider_2.GetId(), self.OnSlidePWM)
        wx.EVT_SLIDER(self, self.slider_3.GetId(), self.OnSlidePWM)
        wx.EVT_CHECKBOX(self, self.checkbox_led.GetId(), self.OnLED)

    def OnSlideFreq(self, event=None):
        spicontroller.setFreq(self.slider_1.GetValue()*65535/100)
    
    def OnSlidePWM(self, event=None):
        spicontroller.setPwm(self.slider_2.GetValue()*65535/100, self.slider_3.GetValue()*65535/100)

    def OnLED(self, event=None):
        spicontroller.setLed(self.checkbox_led.GetValue())

# end of class MainFrame


class MyApp(wx.App):
    def OnInit(self):
        wx.InitAllImageHandlers()
        frame_1 = MainFrame(None, -1, "")
        self.SetTopWindow(frame_1)
        frame_1.Show(1)
        return 1

# end of class MyApp

if __name__ == "__main__":
    app = MyApp(0)
    app.MainLoop()

--- NEW FILE: spicontrol_gui.wxg ---
<?xml version="1.0"?>
<!-- generated by wxGlade 0.3.3 on Fri Jul 16 01:53:43 2004 -->

<application path="spicontrol_gui.py" name="app" class="MyApp" option="0" language="python" top_window="frame_1" encoding="ISO-8859-1" use_gettext="0" overwrite="0" use_new_namespace="1">
    <object class="MainFrame" name="frame_1" base="EditFrame">
        <style>wxDEFAULT_FRAME_STYLE</style>
        <title>SPI Control</title>
        <object class="wxBoxSizer" name="sizer_1" base="EditBoxSizer">
            <orient>wxVERTICAL</orient>
            <object class="sizeritem">
                <flag>wxEXPAND</flag>
                <border>0</border>
                <option>1</option>
                <object class="wxPanel" name="panel_1" base="EditPanel">
                    <style>wxTAB_TRAVERSAL</style>
                    <object class="wxBoxSizer" name="sizer_2" base="EditBoxSizer">
                        <orient>wxVERTICAL</orient>
                        <object class="sizeritem">
                            <flag>wxALL</flag>
                            <border>4</border>
                            <option>0</option>
                            <object class="wxFlexGridSizer" name="grid_sizer_1" base="EditFlexGridSizer">
                                <hgap>0</hgap>
                                <rows>3</rows>
                                <cols>2</cols>
                                <vgap>4</vgap>
                                <object class="sizeritem">
                                    <flag>wxALL</flag>
                                    <border>4</border>
                                    <option>0</option>
                                    <object class="wxStaticText" name="label_1" base="EditStaticText">
                                        <attribute>1</attribute>
                                        <label>Frequency</label>
                                    </object>
                                </object>
                                <object class="sizeritem">
                                    <border>0</border>
                                    <option>1</option>
                                    <object class="wxSlider" name="slider_1" base="EditSlider">
                                        <style>wxSL_HORIZONTAL|wxSL_AUTOTICKS|wxSL_LABELS</style>
                                        <range>1, 100</range>
                                        <value>50</value>
                                        <size>277, -1</size>
                                    </object>
                                </object>
                                <object class="sizeritem">
                                    <flag>wxALL</flag>
                                    <border>4</border>
                                    <option>0</option>
                                    <object class="wxStaticText" name="label_2" base="EditStaticText">
                                        <attribute>1</attribute>
                                        <label>PWM 1</label>
                                    </object>
                                </object>
                                <object class="sizeritem">
                                    <border>0</border>
                                    <option>1</option>
                                    <object class="wxSlider" name="slider_2" base="EditSlider">
                                        <style>wxSL_HORIZONTAL|wxSL_AUTOTICKS|wxSL_LABELS</style>
                                        <range>0, 100</range>
                                        <value>10</value>
                                        <size>277, -1</size>
                                    </object>
                                </object>
                                <object class="sizeritem">
                                    <flag>wxALL</flag>
                                    <border>4</border>
                                    <option>0</option>
                                    <object class="wxStaticText" name="label_3" base="EditStaticText">
                                        <attribute>1</attribute>
                                        <label>PWM 2</label>
                                    </object>
                                </object>
                                <object class="sizeritem">
                                    <border>0</border>
                                    <option>1</option>
                                    <object class="wxSlider" name="slider_3" base="EditSlider">
                                        <style>wxSL_HORIZONTAL|wxSL_AUTOTICKS|wxSL_LABELS</style>
                                        <range>0, 100</range>
                                        <value>20</value>
                                        <size>277, -1</size>
                                    </object>
                                </object>
                            </object>
                        </object>
                        <object class="sizeritem">
                            <flag>wxALL</flag>
                            <border>4</border>
                            <option>0</option>
                            <object class="wxCheckBox" name="checkbox_led" base="EditCheckBox">
                                <label>LED</label>
                            </object>
                        </object>
                    </object>
                </object>
            </object>
        </object>
    </object>
</application>

--- NEW FILE: spicontroller.py ---
#!/usr/bin/env python
# Demonstration GUI for the SPI protocol implementation.
# The application protocol user over SPI is described in the main.c
# source file.
#
# (C) 2004 Chris Liechti <[email protected]>
# this is distributed under a free software license, see license.txt
#
# http://mspgcc.sf.net
#
# Requires Python 2.3+ and the msp430 modules, wxPython 2.4+
#
# $Id: spicontroller.py,v 1.1 2004/07/16 01:19:55 cliechti Exp $

from msp430 import hilspi
from msp430 import HIL
import struct, binascii


#have to slow down SPI function so that the software implementation
#on the MSP430 can cope with it
def delay():
    #can't take HIL.DelayMSec(1) as the operating system rounds that up
    #to 10ms or longer. a value of 0 just makes a very short delay with
    #the function call overhead.
    for i in range(10): HIL.DelayMSec(0)        #hopfully work on every box
    #~ HIL.DelayMSec(0); HIL.DelayMSec(0)       #still works on a P4/2.4GHz
    
hilspi._delay = delay   #patch the delay function with the slower version

#Protocol control characters
SPI_X_IDLE      = '\xff'
SPI_X_DONE      = '\xfe'
SPI_X_BUSY      = '\xfd'
SPI_X_NACK      = '\xf1'
SPI_X_ACK       = '\xf0'

def command(cmd, arg=None):
    """This function send a command to the SPI controller and returns
    the received answer. An IOError is raised when the slave does not
    answer correctly or at all.
    
    The /CS line is activated while the command is active and
    deactivated afterwards.
    
    arg can be a string, which is sent as argument to the command.
    A binary string with the commands answer is returned. If the
    command was rejected by the slave, and IOError is raised.
    """
    HIL.TMS(0)  #enable /CS
    HIL.DelayMSec(1)
    try:
        #send command code
        hilspi.shift(chr(cmd))
        #optionaly, send argument (string)
        if arg is not None:
            if hilspi.shift(arg) != SPI_X_BUSY*len(arg):
                raise IOError("slave not ready while sending arguments")
        #finish command
        byte = hilspi.shift(SPI_X_DONE)
        if byte != SPI_X_BUSY:
            raise IOError("slave not ready while executing command (0x%02x)" % ord(byte))
        #now wait for answer
        answer = ''
        for tries in range(30000):
            byte = hilspi.shift(SPI_X_IDLE)
            if byte < '\xf0':           #data bytes
                answer += byte
            elif byte == SPI_X_ACK:
                break
            elif byte == SPI_X_NACK:
                raise IOError("command failed: %r" % answer)
            elif byte == SPI_X_BUSY:
                pass
        else:
            raise IOError("no answer within time")
        return answer
    finally:
        HIL.TMS(1)  #disable /CS

def reset():
    """Reset the hardware"""
    HIL.RST(0)
    HIL.DelayMSec(50)
    HIL.RST(1)
    HIL.DelayMSec(10)

def init():
    """init parallel port and reset the hardware"""
    hilspi.init()
    reset()

#commands implemented in the example
CMD_IDLE            = 0
CMD_SETLED          = 1
CMD_DELAY           = 2
CMD_SET_FREQ        = 3
CMD_SET_PWM         = 4

def setLed(state):
    """Set LED on or off"""
    return command(CMD_SETLED, state and '\x01' or '\x00')

def setFreq(f):
    """Set PWM base frequency, in timer units 0..65535"""
    #send freq as hex encoded 16 bit binary in little endian format
    return command(CMD_SET_FREQ, binascii.hexlify(struct.pack("<H", f)))

def setPwm(p1, p2):
    """Set both PWM duty cycles, in timer units 0..65535"""
    #send pwm settings as two hex encoded 16 bit binaries in LE format
    return command(CMD_SET_PWM, binascii.hexlify(struct.pack("<HH", p1, p2)))

#test application
if __name__ == '__main__':
    init()
    
    setLed(1)   #switch on LED while the sweep runs
    #~ #sweep in base frequency
    #~ for f in range(0, 1000, 100):
        #~ setFreq(f)
        #~ HIL.DelayMSec(100)
    
    #~ #sweep in pwm modulation
    setFreq(1000)
    for f in range(0, 1000, 100):
        setPwm(f, f)
        HIL.DelayMSec(100)
        
    setFreq(0)  #switch off freq output
    setLed(0)   #switch off LED



-------------------------------------------------------
This SF.Net email is sponsored by BEA Weblogic Workshop
FREE Java Enterprise J2EE developer tools!
Get your free copy of BEA WebLogic Workshop 8.1 today.
http://ads.osdn.com/?ad_id=4721&alloc_id=10040&op=click
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.