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