Jump to content


  • Content Count

  • Joined

  • Last visited

  • Days Won


Reputation Activity

  1. Like
    jsolarski reacted to zeke in The alternative to failure   
    I have Seth Godin's blog in my RSS reader.
    He comes up with some poignant statements a lot of the time.
    Today he talks about people like us.
  2. Like
    jsolarski reacted to xmob in Camera Intervalometer   
    Hello all
    This is my first MSP430 project. I'm an AVR person, but I'm trying to switch to MSP430 because TI really seem to be trying with some excellent support and a brilliant product line up. That, and I also seem to have Launchpads taking over my den.
    Anyway, this originally started out as a simple IR based shutter remote for Nikon cameras. I then upgraded it to an intervalometer. I then added 7 segment displays.
    I built it using the "build then do schematics later" method. I'll get some schematics drawn up and tidy the code. Once that's done, I'll publish it all here.

    IR LED driven by 2N2222 transistor
    2 x 7 segment displays driven by 2 74HC595 shift registers
    Has shutter override so the external trigger sources can be implemented (lightning detector etc)

    To do:

    Add extra input to configure shutter interval without doing it in code
    Support more cameras
    Shutter control using Chronos (hmmm :think: )
    Anything else I might think of

    Sorry about the quality of the video. I filmed it with a Sony Bloggie which is great for outdoor stuff but useless inside.

  3. Like
    jsolarski reacted to longhorn engineer in MSP-EXP430 : Accelerometer and Servo Demo   
    Video uploaded.

  4. Like
    jsolarski reacted to n1ksn in My version of an iambic keyer   
    I was asked to make this a separate post, so here it is. This is my iambic keyer.
    In the spirit of the MSP430, whose strength is very low power sleeping, I put it to sleep at every opportunity, including between starting and stopping dits and dahs. It uses a 32 kHz clock crystal driving ACLK and TimerA, and it sleeps in LPM3 for a quick wakeup. I powered it with a coin cell and didn't bother with an on/off switch since the current draw in idle is less than a microamp. I housed it in a mint tin and it is currently my main keyer in the shack. I don't have a picture of the keyer itself, but it is built on a little piece of perf board and uses point-to-point wiring. The TX output from the chip drives a 2N7000 to key the rig. I've added an attachment with the diagram.
    Here is the code. I use the IAR Embedded Workbench.

    ;------------------------------------------------------------------------------- ; asmTinyKeyer3.s43 - Simple iambic keyer program with pushbutton to ; set speed ; ; This is a simple iambic keyer. If the pushbutton is held down while ; the dit paddle is closed, the speed is incremented by one wpm. If the ; dah paddle is closed instead, the speed is decremented by one wpm. ; ; If a mono plug is inserted prior to power-up (or the dah paddle is closed ; during power-up), the keyer goes into straight key mode until power is ; removed, keying from the dit contact. ; ; Hardware: ; MSP430G2211 with 32.768 clock crystal for ACLK, DCO calibrated at 1 MHz ; for normal system clock. Clock crystal is 12.5 pf type. ; Pin assignments: ; P1.0 = Dit input ; P1.1 = Dah input ; P1.2 = Pushbutton for speed control ; P1.3 = Output to keying MOSFET gate ; XIN, XOUT = 32.768 KHz, 12.5 pf clock crystal ; RST/NMI = 47Kohm pullup resistor, 0.0022 uF pulldown cap ; ; Notes: ; When there is no paddle input, MCU is put in LPM3. It awakens when ; there is a paddle closure. We must use LPM3 rather than LPM4 if a ; clock crystal is used for Timer A, as the crystal-based oscillator does ; not get up to speed quickly enough when the ISR is exited. ; ; During the delays for dits and dahs, the MCU is put in LPM3 with Timer A ; running off ACLK setting the delay time. The timer is run in single shot ; up mode. The associated ISR stops the timer. ; ; The timer count for the current sending speed is determined from a ; table in program flash memory. The time for a single Morse element ; (dit = 1 element on, 1 element off; dah = 3 elements on, 1 element off) ; is calculated by ; ; Element (ms) = 1200 / WPM ; ; where WPM = sending speed in words per minute. If the ACLK frequency ; is changed from 32768 Hz the table will need to be recalculated. ; ; In straight key mode, the processor is put in LPM3 between changes in ; the key closure. ; ; ; Andy Palm 2010.07.26 ;------------------------------------------------------------------------------- ;-------------------Includes, defines, equates---------------------------------- #include "msp430.h" ; #define controlled include file ; I/O pin definitions DIT EQU BIT0 ; Dit contact input DAH EQU BIT1 ; Dah contact input BUTTON EQU BIT2 ; Speed pushbutton input TX EQU BIT3 ; Output to keying MOSFET gate ; Program constants WPM_MIN EQU 10 ; WPM limits, timer count lookup WPM_MAX EQU 30 WPM_INIT EQU 23 ; Default keyer speed ; Must be between limits above ; Register variables ; R4 = Input buffer bits ; R5 = Current speed in wpm ; R7 = WPM table offset ;------------------------------------------------------------------------------- RSEG CSTACK ; Pre-declaration of segment ;-------------------Main Routine------------------------------------------------ RSEG CODE ; Place program in 'CODE' segment Reset: mov.w #SFE(CSTACK), SP ; Set up stack mov.w #WDTPW+WDTHOLD, &WDTCTL ; Stop watchdog timer ; Set DCO for calibrated 1 MHz mov.b &CALBC1_1MHZ, &BCSCTL1 ; Set DCO range mov.b &CALDCO_1MHZ, &DCOCTL ; Set DCO step and modulation mov.b #LFXT1S_0|XCAP_3, &BCSCTL3 ; Select ACLK from LFXT1 ; Set for 12.5 pf internal caps ; Configure Port P1 clr.b &P1OUT ; Set all P1 pins to ground bis.b #0xFF, &P1DIR ; Set all P1 pins to output bic.b #DIT|DAH|BUTTON, &P1DIR ; Set input pins mov.b #DIT|DAH|BUTTON, &P1OUT ; For pull-up direction mov.b #DIT|DAH|BUTTON, &P1REN ; Pull-up on input pins bis.b #DIT|DAH, &P1IES ; Interrupt on falling edge ; Set up Timer A: Clock from ACLK/1, stopped mov.w #TASSEL_1, &TACTL bis.w #CCIE, &TACCTL0 ; Enable interrupts on Compare 0 main: ; Initialize varibles clr.w R4 ; Clear input buffer mov.w #WPM_INIT, R5 ; Initialize speed call #Load_Count ; Timer count for one element call #Straight_Key ; Check for mono plug/straight key Loop: ; Test input pins, set buffer bits accordingly bit.b #DIT, &P1IN ; Dit paddle closed? jnz No_Dit ; No bis.b #DIT, R4 ; Yes, set dit bit in buffer No_Dit: bit.b #DAH, &P1IN ; Dah paddle closed? jnz No_Dah ; No bis.b #DAH, R4 ; Yes, set dah bit in buffer No_Dah: tst.w R4 ; If no pending output, go to sleep jnz Send_Dit ; Otherwise, process input ; Go to LPM3 sleep to wait for paddle input bis.b #DIT|DAH, &P1IE ; Enable P1 pin change interrupt Sleep: clr.b &P1IFG ; Clear any pending interrupts tst.b &P1IFG jnz Sleep bis.w #LPM3|GIE, SR ; Wait for input in LPM3 ; Test input pins after awakening, set buffer accordingly bit.b #DIT, &P1IN ; Dit paddle closed? jnz No_Dit1 ; No bis.b #DIT, R4 ; Yes, set dit bit in buffer No_Dit1: bit.b #DAH, &P1IN ; Dah paddle closed? jnz No_Dah1 ; No bis.b #DAH, R4 ; Yes, set dah bit in buffer No_Dah1: ; If dit buffer bit set, send a dit Send_Dit: bit.b #DIT, R4 ; Dit buffer set? jz No_Send_Dit ; No bit.b #BUTTON, &P1IN ; Speed change button pressed? jnz Send_Dit1 ; No call #Incr_Wpm ; Yes, increment speed Send_Dit1: bic.w #DIT, R4 ; Reset dit buffer bis.b #TX, &P1OUT ; Key TX output bis.w #MC_1|TACLR, &TACTL ; Clear timer and start count up bis.w #LPM3|GIE, SR ; Sleep in LPM3 while waiting bic.b #TX, &P1OUT ; Unkey TX output bit.b #DAH, &P1IN ; Dah paddle closed? jnz No_Dah1A ; No bis.b #DAH, R4 ; Yes, set dah bit in buffer No_Dah1A: bis.w #MC_1|TACLR, &TACTL ; Clear timer and start count up bis.w #LPM3|GIE, SR ; Sleep in LPM3 while waiting No_Send_Dit: ; Test input pins, set buffer accordingly bit.b #DIT, &P1IN ; Dit paddle closed? jnz No_Dit2 ; No bis.b #DIT, R4 ; Yes, set dit bit in buffer No_Dit2: bit.b #DAH, &P1IN ; Dah paddle closed? jnz No_Dah2 ; No bis.b #DAH, R4 ; Yes, set dah bit in buffer No_Dah2: ; If dah buffer bit set, send a dah Send_Dah: bit.b #DAH, R4 ; Dah buffer set? jz No_Send_Dah ; No bit.b #BUTTON, &P1IN ; Speed change button pressed? jnz Send_Dah1 ; No call #Decr_Wpm ; Yes, decrement speed Send_Dah1: bic.w #DAH, R4 ; Reset dah buffer bis.b #TX, &P1OUT ; Key TX output bis.w #MC_1|TACLR, &TACTL ; Clear timer and start count up bis.w #LPM3|GIE, SR ; Sleep in LPM3 while waiting bis.w #MC_1|TACLR, &TACTL ; Repeat twice for a three element bis.w #LPM3|GIE, SR ; long dah bis.w #MC_1|TACLR, &TACTL bis.w #LPM3|GIE, SR bic.b #TX, &P1OUT ; Unkey TX output bit.b #DIT, &P1IN ; Dit paddle closed? jnz No_Dit2A ; No bis.b #DIT, R4 ; Yes, set dit bit in buffer No_Dit2A: bis.w #MC_1|TACLR, &TACTL ; Clear timer and start count up bis.w #LPM3|GIE, SR ; Sleep in LPM3 while waiting No_Send_Dah: jmp Loop ;-------------------Interrupt Service Routines---------------------------------- ;------------------------------------------------------------------------------- Input_ISR: ; Interrupt service routine for inputs on Port P1 bic.b #DIT|DAH, &P1IE ; Disable P1 pin change interrupt Input_ISR1: clr.b &P1IFG ; Clear any pending interrupts tst.b &P1IFG jnz Input_ISR1 bic.w #LPM3|GIE, 0(SP) ; Clear LP and GIE bits on exit reti ;------------------------------------------------------------------------------- TA0_ISR: ; Interrupt service routine for TACCR0, called when TAR = TACCR0. bic.w #MC_1, &TACTL ; Stop timer bic.w #LPM3|GIE, 0(SP) ; Clear LP and GIE bits on exit reti ;-------------------Subroutines------------------------------------------------- ;------------------------------------------------------------------------------- ; Run in straight key mode, keying from dit paddle. Straight_Key: bit.b #DAH, &P1IN ; Dah paddle closed? jz SK1 ret ; No, return to normal operation SK1: bit.b #DIT, &P1IN ; Dit contact closed? jnz SK2 bis.b #TX, &P1OUT ; Yes, key TX output bic.b #DIT, &P1IES ; Interrupt on leading edge jmp SK3 SK2: bic.b #TX, &P1OUT ; No, unkey TX output bis.b #DIT, &P1IES ; Interrupt on falling edge SK3: bis.b #DIT, &P1IE ; Enable P1 pin change interrupt SK4: clr.b &P1IFG ; Clear any pending interrupts tst.b &P1IFG jnz SK4 bis.w #LPM3|GIE, SR ; Wait for change in LPM3 jmp SK1 ret ; Should never get here ;------------------------------------------------------------------------------- ; Increment speed by one wpm in R5 and load new timer count Incr_Wpm: cmp.w #WPM_MAX, R5 ; wpm < WPM_MAX? jlo Incr_Wpm1 ret ; No, return Incr_Wpm1: inc.w R5 ; Yes, increment wpm call #Load_Count ; and load new timer count ret ;------------------------------------------------------------------------------- ; Decrement speed by one wpm in R5 Decr_Wpm: dec.w R5 cmp.w #WPM_MIN, R5 ; wpm - 1 >= WPM_MIN? jhs Decr_Wpm1 inc.w R5 ; No, restore value ret ; and return Decr_Wpm1: call #Load_Count ; Yes, load new timer count ret ;------------------------------------------------------------------------------- ; Given wpm speed in R5 load Timer A count for single time element. ; Uses R7 for calculation of table offset value. Load_Count: mov.w R5, R7 ; Calculate table offset sub.w #WPM_MIN, R7 ; = WPM - WPM_MIN rla.w R7 ; Multiply by 2 for word addr mov.w WPM_Table(R7), &TACCR0 ; Load timer ret ;-------------------Flash RAM Data---------------------------------------------- ;------------------------------------------------------------------------------- ; Table giving Timer A count for Words per Minute when using clock crystal ; at 32768 Hz for timer clock, divide by 1. The formula for the table ; values is ; ; Count = (1.2 / WPM) / (1 / 32768) = 39321.6 / WPM ; where ; Length of dit/element = 1.2 / WPM seconds ; RSEG DATA16_C ; Segment for flash data WPM_Table: DW 3932 ; WPM 10 DW 3575 ; WPM 11 DW 3277 ; WPM 12 DW 3025 ; WPM 13 DW 2809 ; WPM 14 DW 2621 ; WPM 15 DW 2458 ; WPM 16 DW 2313 ; WPM 17 DW 2185 ; WPM 18 DW 2070 ; WPM 19 DW 1966 ; WPM 20 DW 1872 ; WPM 21 DW 1787 ; WPM 22 DW 1710 ; WPM 23 DW 1638 ; WPM 24 DW 1573 ; WPM 25 DW 1512 ; WPM 26 DW 1456 ; WPM 27 DW 1404 ; WPM 28 DW 1356 ; WPM 29 DW 1311 ; WPM 30 ;-------------------Interrupt Vectors------------------------------------------- ; Interrupt vector table COMMON INTVEC ; Segment for vectors in flash ORG PORT1_VECTOR DW Input_ISR ORG TIMERA0_VECTOR DW TA0_ISR ORG RESET_VECTOR DW Reset END

    The schematic has a comment about adding an on/off switch. This is only a convenience in case one wants to use a straight key through the keyer in the shack, which is unlikely (just use a Y-cable to the rig instead). The straight key feature is always there. I put it in as a feature in case I built one of these keyers inside a QRP (low-power) portable rig. Then I can insert a paddle or straight key in the same jack before power-up, and the software does the right thing when power is applied. By the way, this is an iambic keyer and I sometimes use dual paddles, but personally I prefer a single paddle which doesn't use the iambic-ness.
    If I want to store the keyer, I slip a piece of thin plastic between the battery and the tab on the battery holder. Even without doing this, my calculations show that the battery will self-discharge long before it is used up by this keyer.
    Andy N1KSN
  5. Like
    jsolarski reacted to MarkoeZ in EZ430 Chronos, the TI watch. First tests and quick guide.   
    Well my Chronos Watch arrived this afternoon, and i figured i might as well do another newbies intro.
    So without further interrupt:

    And if you are new to the chronos, this next video might be useful. Quick guide to hacking the firmware in code restricted CCS:

  6. Like
    jsolarski reacted to nexusone1984 in 4X4X4 LED cude   
    Been busy with a lot of other stuff... but after a little time here and there put together a 4x4x4 LED Cube.
    Soldering the LED's took me forever....
    I used Common Cathode configuration for the LED's, this way logic 1 turns on the LED. and Logic 1 also turns on a Row transistor.
    Simple little demo.

    Parts: Launchpad board, 3 x 74HC595 8-bit shift registers, 4 x 2N3904 NPN transistors, 64 Yellow LED's.
  7. Like
    jsolarski reacted to chibiace in Launchpad with zif socket   
    heres a photo of a launchpad i soldered a 14pin zif socket to, also originally i had female headers on the side but changed them to male and put them underneath so as to mount on a breadboard.

    much faster to program large numbers of chips, now if i only had a 20 pdip socket...
  8. Like
    jsolarski reacted to RobG in Charlieplex driver   
    I am thinking of making another board, high current Charlieplex driver.
    My idea is to have two 595s and 24 transistors (I am planning on using BC807DS so the actual number will be 16.)
    Supply voltage 3.6V, base resistors 2k2, segment resistors 22-56ohms.
    One thing I am missing is a protection circuit. I want to use 74HC123 which would be triggered by latch.
    This is what I have so far:

  9. Like
    jsolarski reacted to zeke in Electronics Tip: Antistatic Mat   
    Winter is coming so the air will be dryer. At least it will where I live.
    You can generate a couple 1000 Volts of static electricity just by getting up off of your chair. So save yourself some circuit troubleshooting grief get an anti-static mat.
    I have both a Desco and a 3M anti-static mat.
    The 3M one is cheaper for some reason.
  10. Like
    jsolarski reacted to RobG in Audio Spectrum Analyzer   
    My board and MSGEQ7 chip in action.
    Three 5x7 matrix displays (15x7) are connected to my 595 expander board.
    MSGEQ7 does all the hard work here, nothing fancy, no FFT.

  11. Like
    jsolarski reacted to RobG in Question about batteries and voltages   
  12. Like
    jsolarski got a reaction from bluehash in msp430-gcc: delay loops optimised out   
    FYI if you need more delay options...... http://www.43oh.com/forum/viewtopic.php?f=10&t=65
  13. Like
    jsolarski got a reaction from smiffy in msp430-gcc: delay loops optimised out   
    FYI if you need more delay options...... http://www.43oh.com/forum/viewtopic.php?f=10&t=65
  14. Like
    jsolarski reacted to oPossum in Dallas/Maxim One Wire Library   
    Here is a basic library for 1-wire communication. It works with CPU frequency of 1 MHz or higher. Carefully crafted assembly code is used to allow operation over a wide CPU clock frequency range.
    There are only two functions. One for setup and the other for all communication tasks.

    // one_wire.h void one_wire_setup(volatile unsigned char *dir, volatile unsigned char *in, unsigned bitmask, unsigned mhz); int owex(int data, unsigned bits);
    The library is initialized by a call to one_wire_setup(). The arguments specify the I/O pin and clock frequency.
    An example for P1.4 at 16 MHz...
    one_wire_setup(&P1DIR, &P1IN, 0x10, 16);
    The setup function can be called repeatedly to allow communication on more than one I/O pin.
    The owex() [One Wire EXchange] function does bus reset, tx and rx.
    To reset the bus and detect if any devices are present, just call it with a bit count of zero....
    p = owex(0, 0);
    The returned value will be -1 (0xFFFF) if any devices are detected, or 0 if none are detected.
    To send data...
    owex(0xCC, 8); // Skip ROM command
    The returned value should match the data sent, if it does not then there is a bus problem.
    To receive data, use -1 (0xFFFF) for the tx data value...
    d = owex(-1, 8); // Get 8 bits
    1 to 16 bits can be sent/received at once.
    This is the core code...

    .def owex ; int owex(int data, unsigned bit_count) .def owdport .def owiport .def owbit .def owtiming .bss owdport, 2 ; Direction port .bss owiport, 2 ; Input port .bss owbit, 2 ; Port bitmask .bss owtiming, 0 ; Timing array .bss owda, 2 ; 28 Zero .bss owdb, 2 ; 33 .bss owdc, 2 ; 39 .bss owdd, 2 ; 7 One .bss owde, 2 ; 8 .bss owdf, 2 ; 85 .bss owdg, 2 ; 500 Reset .bss owdh, 2 ; 50 .bss owdi, 2 ; 450 owex ; tst R13 ; Reset? jeq owrst ; Yes... push R11 ; Save R11, R13 push R13 ; clr R13 ; Clear bit count ; owloop ; --- Tx/Rx bit loop rra R12 ; Get tx bit jc owone ; If one... ; ; - Send and verify zero mov &owda, R15 ; nop ; mov &owdport, R14 ; Bus low bis.b &owbit, 0(R14) ; ; call #owdelay ; Delay 28 us ; mov &owiport, R14 ; Sample bus mov.b @R14, R14 ; bit &owbit, R14 ; rrc R11 ; ; mov &owdb, R15 ; Delay 33 us call #owdelay ; ; mov &owdc, R15 ; mov &owdport, R14 ; Bus open bic.b &owbit, 0(R14) ; ; jmp ownext ; Delay 39 us ; owone ; - Send one and read bit mov &owdd, R15 ; tst R15 ; mov &owdport, R14 ; Bus low bis.b &owbit, 0(R14) ; ; jn owoneo ; Delay 7 us owdlyd ; sub #8, R15 ; nop ; jc owdlyd ; subc R15, PC ; nop ; nop ; nop ; owoneo ; bic.b &owbit, 0(R14) ; Bus open ; jc owones ; Delay 8 us mov &owde, R15 ; owdlye ; sub #8, R15 ; nop ; jc owdlye ; subc R15, PC ; nop ; nop ; nop ; owones ; mov &owiport, R14 ; Sample bus mov.b @R14, R14 ; bit &owbit, R14 ; rrc R11 ; ; mov &owdf, R15 ; Delay 85 us ownext ; call #owdelay ; ; - Next bit inc R13 ; Increment bit count cmp R13, 0(SP) ; Compare bit count jne owloop ; Loop if not done... owrxa ; - Align rx data cmp #16, R13 ; Rx data aligned? jeq owrex ; Yes.. rra R11 ; Shift in a zero bit inc R13 ; Inc bit count jmp owrxa ; Next bit... owrex ; mov R11, R12 ; Get rx data to R12 pop R13 ; Restore R11, R13 pop R11 ; ret ; Return ; ; owrst ; - Reset and presence detect mov &owdport, R14 ; Bus low bis.b &owbit, 0(R14) ; ; mov &owdg, R15 ; Delay 500 us call #owdelay ; ; bic.b &owbit, 0(R14) ; Bus open ; mov &owdh, R15 ; Delay 50 us call #owdelay ; ; mov &owiport, R14 ; Sample bus mov.b @R14, R14 ; bit &owbit, R14 ; subc R12, R12 ; ; mov &owdi, R15 ; Delay 450 us ;jmp owdelay ; and return ; owdelay ; sub #8, R15 ; nop ; jc owdelay ; subc R15, PC ; nop ; nop ; nop ; ret ; ; .end ;
    Demo program to read DS1820/1822 temperature sensor is included in zip file.
  15. Like
    jsolarski reacted to andy1324 in Strotoscobic guitar tuner/small devboard   
    -- Update 10.11.2011 --
    Okay I finally had a change to test it with a real guitar and found some pretty bad hindsights on the code, They have now been corrected and at least one guitar was tuned succesfully with the device
    This is my entry for the August POTM, I will update details here.
    Okay so it's a small strotoscobic guitar tuner/development board for msp430 in 14 pin tssop package. It provides 6 charlieplexed leds and two high intensity leds for strobe effect/whatever, I used msp430g2211 because I had two on hand but I think any 14 pin msp430 should work.
    The main idea here was just to test seeedstudios fusion pcb service so I needed a small 5x5cm board and somehow I decided this kind of tuner would be nice, I have seen atleast few avr based ones so it is not a new idea in any way but this is the first msp430 based one that I know of. The device seems to work nicely but since I do not own nor can I play guitar it has not yet been tested =). Im not sure how accurate the frequency needs to be but I think it should be accurate enough for ballpark tuning and I will test it at some point.
    The design itself is pretty simple and if I would do it again there are few improvements to be made, firstly the high intensity leds could be directly connected to pwm outputs as now only ccr0 is used and I do wonder what I was thinking when I made the board =). Also as there is one extra pin maybe adding more leds by charlieplexing would have been nice. Also the resistor values for both the big leds and the charlieplexed ones must be chosen according to the used parts and some testing is propably needed. I made two and tweaked the values a bit because as can be seen from the action shot this version has very dim indicator leds and the large ones are really bright.
    Here's a rendered view of the device

    and bad photos of front, back and "action" shot

    And the code:
    I have tried to make it very low power on sleep but I think it can still be improved for example by larger pull-up resistors etc. I measured it at less than 1uA but the meter I had can't really measure currents so low so it can be a lot less. In use the current consumption jumps to bit less than 20mA but that can be changed by increasing the led current limiting resistors and the strobe leds are very bright reds so there is room to improve the design.

    // #include // #include // #include #include #include /* Defines for charlieplexed leds */ #define LED1 P1DIR &= ~BIT2; P1DIR |= 0x3; P1OUT &= ~BIT0; P1OUT |= BIT1 #define LED2 P1DIR &= ~BIT2; P1DIR |= 0x3; P1OUT &= ~BIT1; P1OUT |= BIT0 #define LED3 P1DIR &= ~BIT0; P1DIR |= 0x6; P1OUT &= ~BIT1; P1OUT |= BIT2 #define LED4 P1DIR &= ~BIT0; P1DIR |= 0x6; P1OUT &= ~BIT2; P1OUT |= BIT1 #define LED5 P1DIR &= ~BIT1; P1DIR |= 0x5; P1OUT &= ~BIT0; P1OUT |= BIT2 #define LED6 P1DIR &= ~BIT1; P1DIR |= 0x5; P1OUT &= ~BIT2; P1OUT |= BIT0 /* note period in us/2 */ #define E2 (12134/2) // 82.407 Hz #define A2 (9090/2) // 110.00 Hz #define D3 (6810/2) // 146.83 Hz #define G3 (5102/2) // 196.00 Hz #define B3 (4050/2) // 246.94 Hz #define E4 (3034/2) // 329.63 Hz //#define F_CPU 1000000 // Cpu speed is 1Mhz which is easily enough for this application #define POWER_ON_COUNT 15 void wait(int cycles) { unsigned int i; volatile int j; for(i=0; i { j++; } } void SetupHardware(void); void SetupTimer(void); inline void sleep_prepare(void); void Set_DCO(unsigned int Delta); volatile unsigned char calibrate=0; volatile unsigned int calibtime=0; volatile unsigned int sleeptime; volatile unsigned int period = E2; volatile unsigned char mode; volatile unsigned char btn_flag = 1; volatile unsigned int wakeup_flag; volatile unsigned int toglestate = 0; volatile unsigned int ledofftime = (E2 >> 1); int main(void) { SetupHardware(); // Init hardware wait(0xfffe); // Small delay before calibration Set_DCO(244); // Calibrate 1Mhz SetupTimer(); // Init TIMERA eint(); // Enable interrupts while(1) { if(btn_flag) // Button was pressed { btn_flag = 0; // Clear button pressed flag if(calibrate) { calibrate = 0; wait(0xfffe); // Small delay before calibration Set_DCO(244); // Calibrate DCO with external crystal SetupTimer(); // Set timerA back to application use. } switch(mode) // Change mode if needed { case 0: period = E2; LED1; break; case 1: period = A2; LED2; break; case 2: period = D3; LED3; break; case 3: period = G3; LED4; break; case 4: period = B3; LED5; break; case 5: period = E4; LED6; break; } ledofftime = period >> 2; // shuts down the leds so the duty cycle is ~12.5% TACCR0 = period; TACCR1 = ledofftime; _BIS_SR(LPM0_bits + GIE); // Shut down cpu, only interrupts and timers using SMCLK needed } } return 0; } interrupt (WDT_VECTOR) Watchdog_timer_interrupt(void) { sleeptime++; // Increase shutdown timer if(sleeptime > 30) // If 30 seconds have elapsed go to sleep { sleeptime = 0; sleep_prepare(); // Prepare hardware for low power mode wakeup_flag = 1; // Set flag to notify that LPM was active _BIS_SR_IRQ(LPM4_bits + GIE); // Enter LPM4 with interrupts } } interrupt (TIMERA0_VECTOR) TimerInterrupt(void) //Timer CCR0 interrupt { if(toglestate) { P1OUT |= BIT4; } else { P1OUT |= BIT5; } toglestate = !toglestate; } interrupt (TIMERA1_VECTOR) LedOffInterrupt(void) { switch( TAIV ) { case 2: // CCR1 interrupt P1OUT &= ~(BIT4 | BIT5); break; default: break; } } interrupt (PORT1_VECTOR) Sw12Interrupt(void) { sleeptime = 0; switch(P1IFG&0xC0) { case BIT6: P1IFG = 0x0; btn_flag = 1; if(!wakeup_flag) { if(++mode > 5) { mode = 0; } } break; case BIT7: P1IFG = 0x0; btn_flag = 1; break; default: btn_flag = 1; P1IFG = 0x0; break; } if(wakeup_flag && btn_flag) { calibtime++; // Increase calibration constant, calibrate device every POWER_ON_COUNT boots WDTCTL = WDT_ADLY_1000 ; //WDT interval mode on ACLK for 1000ms IE1 |= WDTIE; // Enable watchdog interval interrupt wakeup_flag = 0; if(calibtime > POWER_ON_COUNT) { calibrate = 1; } _BIC_SR_IRQ(LPM4_bits); // Exit LPM4 mode } // Exit LPM0 mode to run main loop, could use LPM3 etc but leds take // so much power that it's basically a moot point. _BIC_SR_IRQ(LPM0_bits); } inline void sleep_prepare(void) { P1DIR = ~(BIT6 | BIT7); // Set everything but button inputs to output P1OUT = (BIT6 | BIT7); // Set SW1 and SW2 pull-up resistors high WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer IE1 &= ~WDTIE; // Disable watchdog interrupt } void SetupHardware(void) { WDTCTL = WDT_ADLY_1000 ; //WDT interval mode on ACLK 1000ms BCSCTL1 = CALBC1_1MHZ; //Calibrated 1Mhz clock DCOCTL = CALDCO_1MHZ; IE1 |= WDTIE; // Enable watchdog interval interrupt BCSCTL3 |= XCAP_3; // Crystal oscillator load capacitor setting, 12.5pf P1DIR |= (BIT4 | BIT5); // Set HC led pin directions to output P1OUT &= ~(BIT4 | BIT5); P1DIR &= ~(BIT6 | BIT7); // Set SW1 and SW2 pins to input P1REN |= (BIT6 | BIT7); // Enable SW1 and SW2 pull-up resistors P1OUT |= (BIT6 | BIT7); // Set SW1 and SW2 pin pull-up resistors high; P1IES |= (BIT6 | BIT7); // Set SW1 and SW2 interrupt on high->low transition P1IE |= (BIT6 | BIT7); //Enable SW1 and SW2 interrupts } void SetupTimer(void) { TACTL = TASSEL_2 + ID_0 + MC_1 ; // set timer to 1Mhz and continuous mode TACCR0 = period; TACCR1 = ledofftime; TAR = 0; TACCTL0 = CM_0 + CCIE + CCIFG; // Enable CCR0 interrupts TACCTL1 = CM_0 + CCIE + CCIFG; // Enable CCR0 interrupts } /* Calbiration code from DCO calibration thread page 2 by zeke, only modified to stop watchdog interval timer and to start it again in the end*/ //-------------------------------------------------------------------------- void Set_DCO(unsigned int Delta) // Set DCO to F_CPU //-------------------------------------------------------------------------- { unsigned int Compare, Oldcapture = 0; WDTCTL = WDTPW + WDTHOLD; IE1 &= ~WDTIE; BCSCTL1 |= DIVA_3; // ACLK = LFXT1CLK/8 TACCTL0 = CM_1 + CCIS_1 + CAP; // CAP, ACLK TACTL = TASSEL_2 + MC_2 + TACLR; // SMCLK, cont-mode, clear while (1) { while (!(CCIFG & TACCTL0)); // Wait until capture occured TACCTL0 &= ~CCIFG; // Capture occured, clear flag Compare = TACCR0; // Get current captured SMCLK Compare = Compare - Oldcapture; // SMCLK difference Oldcapture = TACCR0; // Save current captured SMCLK if (Delta == Compare) break; // If equal, leave "while(1)" else if (Delta < Compare) { DCOCTL--; // DCO is too fast, slow it down if (DCOCTL == 0xFF) // Did DCO roll under? if (BCSCTL1 & 0x0f) BCSCTL1--; // Select lower RSEL } else { DCOCTL++; // DCO is too slow, speed it up if (DCOCTL == 0x00) // Did DCO roll over? if ((BCSCTL1 & 0x0f) != 0x0f) BCSCTL1++; // Sel higher RSEL } } TACCTL0 = 0; // Stop TACCR0 TACTL = 0; // Stop Timer_A BCSCTL1 &= ~DIVA_3; // ACLK = LFXT1CLK WDTCTL = WDT_ADLY_1000 ; //WDT interval mode on ACLK for 1000ms IE1 |= WDTIE; // Enable watchdog interval interrupt }
    Also attached is project zip file which SHOULD include everything and also the gerbers I sent to seeed. Let me know if I forgot some files from the package
    BOM for the parts I used:
    resistors and caps as usual.
    32.768KHz crystal: digikey part 539-9032-ND
    mosfets were BSS123 and BSS138 (I made two of these and for some reason used different parts in them but either one will work fine) digikey part BSS123CT-ND and BSS138W-FDICT-ND
    Battery holder digikey part BAT-HLD-001-ND
    Buttons: Mouser part 101-TS6111T1602-EV
    Large leds: digikey part 754-1274-ND
    small leds were some random green 0805 smd:s
  16. Like
    jsolarski reacted to nuetron in MSP430 with 8051-based bus   
    Hi guys!
    I've been working on a program that will read a byte from an AT computer keyboard, and print it on a 16x2 LCD display.
    I'm also working on a function that will read the visible portion of the display, and save it in an I2C EEPROM.
    Using RobG's I2C code, I was able to successfully interface an HD44780 display to my '2231, via a PCF8574 port expander.
    Since I now have a bidirectional 8-bit parallel bus, I will connect a W83C43 keyboard controller to it, thus enabling a very large input range to my micro.
    The schematic:
  17. Like
    jsolarski got a reaction from bluehash in CCS 4 add ons?   
    i dont know if this is it but it has some plugins
  18. Like
    jsolarski got a reaction from gwdeveloper in Capsense Interrupt?   
    Yes it can, you will have to look into the specific cap sense application note
    I have not personally done anything with the capsense library but it should help you get a good start
  19. Like
    jsolarski got a reaction from inru0716 in about UCS in MSP430x5xx   
    DCO and MOD bits set the exact frequency for the selected range DCORSEL_3
    look at it this way
    DCORSELx bits select the frequency range
    DCOx bits selects the base frequency
    MODx bits selects the modulation (check the user guide for DCO modulator)
    I hope this answers your question, but this is as far as my understanding goes for the UCS.
    if you need more help you may want to rephrase your question too
  20. Like
    jsolarski reacted to RobG in Color Organ   
    My MIDI Light Controller modified to work as color organ.
    I was working on implementing Goertzel for detecting frequencies when mtlevine0 mentioned in his post this nifty little chip called MSGEQ7. After adding few little parts and few extra lines of code, here it is, a 10ch color organ. 7 channels are driven directly from the chip, 3 are combination of the other channels.

  21. Like
    jsolarski reacted to oPossum in 256 x 192 graphics display using Fraunchpad - preview   
    Using FRAM for a frame buffer seems to have some problems. There are video artifacts that I assumed where due to instruction cache misses causing clock jitter, but running at 8 MHz clock did not fix that problem. I also may have damaged some of the FRAM - there are some bits that are no longer programmable.
    So, I am going to switch to a MSP430F5418A and use part of the 16K SRAM as frame buffer. That should fix the video artifact problem and also be a little faster.
    I added some primitive 3D functions, so here is the obligatory 3D cube (with very noticeable artifacts)...

    All three axis are rotated concurrently. This is done entirely with 16.16 bit fixed point math. Here is some of the code...

    void rotate_3d(T3DP const *s, T3DP *d, unsigned n, int rx, int ry, int rz) { long sx, cx, sy, cy, sz, cz; long yx, zx, xy; register long x, y, z; const unsigned long focal_length = 200; unsigned long scale_factor; sx = sin(rx); cx = cos(rx); // Get sin/cos of rotations sy = sin(ry); cy = cos(ry); sz = sin(rz); cz = cos(rz); while(n--) { x = s->x; y = s->y; z = s->z; // Get source point zx = ( y * sx + z * cx) >> 16; // Rotation around x axis yx = ( y * cx - z * sx) >> 16; xy = (zx * sy + x * cy) >> 16; // Rotation around y axis z = (zx * cy - x * sy) >> 16; y = (xy * sz + yx * cz) >> 16; // Rotation around z axis x = (xy * cz - yx * sz) >> 16; // Perspective scale_factor = (focal_length << 16) / (focal_length - z); d->x = (x * scale_factor) >> 16; d->y = (y * scale_factor) >> 16; d->z = z; ++s; ++d; // Inc source and dest pointers } } static const unsigned st[90] = { // sine table 0 to 89 degrees 16 bit fraction 0, 1144, 2287, 3430, 4572, 5712, 6850, 7987, 9121, 10252, 11380, 12505, 13626, 14742, 15855, 16962, 18064, 19161, 20252, 21336, 22415, 23486, 24550, 25607, 26656, 27697, 28729, 29753, 30767, 31772, 32768, 33754, 34729, 35693, 36647, 37590, 38521, 39441, 40348, 41243, 42126, 42995, 43852, 44695, 45525, 46341, 47143, 47930, 48703, 49461, 50203, 50931, 51643, 52339, 53020, 53684, 54332, 54963, 55578, 56175, 56756, 57319, 57865, 58393, 58903, 59396, 59870, 60326, 60764, 61183, 61584, 61966, 62328, 62672, 62997, 63303, 63589, 63856, 64104, 64332, 64540, 64729, 64898, 65048, 65177, 65287, 65376, 65446, 65496, 65526 }; long sin(int d) { while(d < 0) d +=360; while(d > 359) d -= 360; if(d < 180) { if(d < 90) // 0 -> 89 return st[d]; else if(d > 90) // 91 -> 179 return st[180 - d]; else return 65536L; // 90 } else { if(d < 270) // 180 -> 269 return -(long)st[d - 180]; else if(d > 270) // 271 -> 359 return -(long)st[360 - d]; else return -65536L; // 270 } } long cos(int d) { return sin(d + 90); }

  22. Like
    jsolarski reacted to ike in equation optimization help -BPM calculations   
    BPM = 15000 / (milliseconds >> 2)
    BPM = 7500 / (milliseconds >> 3)
    BPM = 3750 / (milliseconds >> 4)
    BPM = 1875 / (milliseconds >> 5)
  23. Like
    jsolarski reacted to oPossum in MSP430 support for 430FR (FRAM) parts?   
    P3DIR = 0xF0; P3OUT = 0xF0;
  24. Like
    jsolarski reacted to oPossum in equation optimization help -BPM calculations   
    BPM = 30000 / (milliseconds >> 1)
  25. Like
    jsolarski reacted to roger430 in Magic Eight Ball   
    Here's my first attempt at having the TI Launchpad do something a little more than flashing LEDs. I used this project to learn more about the MSP430 interrupts, GPIO, low power mode and timers. It operates similar to the old "Magic Eight Ball" in that you ask a question, press S2 (P1.3) on the Launchpad, watch the blinking lights and look at the answer in a terminal program such as "minicom" in Linux or "putty.exe" in WinXP/Vista/Win7. You have to configure your comm program to read what ever port the Launchpad uses (for my Linux box it is /dev/ttyACM0 and for my Windows 7 box it was COM5 - the options are 9600,8,N,1 no flow control). I imagine a serial LCD device could be used, however, I don't have one. If anyone tries this project with a serial LCD display, please let me know how it works. I'm sure my code could be cleaned up to be more efficient, however, as I said I'm learning! The device pulls about 75-80 uA when it's waiting for a button press in LPM0 mode. Here is the code:

    //****************************************************************************** // Magic Eight Ball Project // UART code taken from msp430g2xx1_ta_uart9600.c example file. // (D. Dang, Texas Instuments Inc.) // MSP430G2xx1 Demo - Timer_A, Ultra-Low Pwr UART 9600 Echo, 32kHz ACLK // ACLK = TACLK = LFXT1 = 32768Hz, MCLK = SMCLK = default DCO // //* An external watch crystal is required on XIN XOUT for ACLK *// // // Description: Simple Magic Eight Ball adaptation utilizing the MSP430 Launchpad. // To operate, simply connect Launchpad to PC USB port and fire up a comm program // such as "minicom" in Linux or "putty.exe" in Windows XP/Vista/7. (Be sure to // configure your comm program for whatever comm port the Launchpad uses.) // Press S1 (Reset) on Launchpad. "Magic Eight Ball Ready" should appear in // terminal window. // Ask your question, press S2, watch the blinking lights and answer will appear // in the terminal window. // // MSP430G2xx1 // ----------------- // /|\| XIN|- // | | | 32kHz // --|RST XOUT|- // <---|P1.3 Switch | // | CCI0B/TXD/P1.1|--------> // | | 9600 8N1 // | CCI0A/RXD/P1.2|<-------- // // R.G. Rioux // July 2011 // Built with CCS Version //****************************************************************************** #include "msp430g2231.h" #include // rand() & srand() //------------------------------------------------------------------------------ // Hardware-related definitions //------------------------------------------------------------------------------ #define UART_TXD 0x02 // TXD on P1.1 (Timer0_A.OUT0) #define UART_RXD 0x04 // RXD on P1.2 (Timer0_A.CCI1A) #define BUTTON BIT3 // Button on P1.3 //------------------------------------------------------------------------------ // Conditions for 9600 Baud SW UART, SMCLK = 1MHz //------------------------------------------------------------------------------ #define UART_TBIT_DIV_2 (1000000 / (9600 * 2)) #define UART_TBIT (1000000 / 9600) //------------------------------------------------------------------------------ // Global variables used for full-duplex UART communication //------------------------------------------------------------------------------ unsigned int txData; // UART internal variable for TX unsigned char rxBuffer; // Received UART character //------------------------------------------------------------------------------ // Global variables in program //------------------------------------------------------------------------------ unsigned int randnum = 0; int i; char msgflag = 0; static char *answer[10] = { "Yes, in due time.", "My sources say no.", "Definitely not.", "Yes.", "Probably.", "I have my doubts.", "Who knows?", "Looking good!", "Go for it!", "Forget about it!" }; //------------------------------------------------------------------------------ // Function prototypes //------------------------------------------------------------------------------ void TimerA_UART_init(void); void TimerA_UART_tx(unsigned char byte); void TimerA_UART_print(char *string); //------------------------------------------------------------------------------ // main() //------------------------------------------------------------------------------ void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer DCOCTL = 0x00; // Set DCOCLK to 1MHz BCSCTL1 = CALBC1_1MHZ; DCOCTL = CALDCO_1MHZ; P1OUT = 0x00; // Initialize all GPIO P1SEL = UART_TXD; // Timer function for TXD pin P1DIR = 0xFF & ~BUTTON; // Set all pins but BUTTON to output P2OUT = 0x00; P2SEL = 0x00; P2DIR = 0xFF; P1IE |= BUTTON; //P1.3 interrupt enabled P1IFG = 0x00; //Clear all interrupt flags __enable_interrupt(); TimerA_UART_init(); // Start Timer_A UART TimerA_UART_print("Magic Eight Ball v0.01\r\n"); TimerA_UART_print("READY.\r\n"); while (1) { _bis_SR_register(LPM0_bits + GIE); if (msgflag == 1) { P1OUT |= BIT6; for (i=1;i<=25;i++) { P1OUT ^= BIT0 + BIT6; // Flash LEDs __delay_cycles(100000); } P1OUT &= ~(BIT0 + BIT6); TimerA_UART_print(answer[randnum]); // Send message TimerA_UART_print("\r\n"); // Send CRLF msgflag = 0; // Reset message flag } } } //------------------------------------------------------------------------------ // Function configures Timer_A for full-duplex UART operation //------------------------------------------------------------------------------ void TimerA_UART_init(void) { TACCTL0 = OUT; // Set TXD Idle as Mark = '1' TACCTL1 = SCS + CM1 + CAP + CCIE; // Sync, Neg Edge, Capture, Int TACTL = TASSEL_2 + MC_2; // SMCLK, start in continuous mode } //------------------------------------------------------------------------------ // Outputs one byte using the Timer_A UART //------------------------------------------------------------------------------ void TimerA_UART_tx(unsigned char byte) { while (TACCTL0 & CCIE); // Ensure last char got TX'd TACCR0 = TAR; // Current state of TA counter TACCR0 += UART_TBIT; // One bit time till first bit TACCTL0 = OUTMOD0 + CCIE; // Set TXD on EQU0, Int txData = byte; // Load global variable txData |= 0x100; // Add mark stop bit to TXData txData <<= 1; // Add space start bit } //------------------------------------------------------------------------------ // Prints a string over using the Timer_A UART //------------------------------------------------------------------------------ void TimerA_UART_print(char *string) { while (*string) { TimerA_UART_tx(*string++); } } //------------------------------------------------------------------------------ // Timer_A UART - Transmit Interrupt Handler //------------------------------------------------------------------------------ #pragma vector = TIMERA0_VECTOR __interrupt void Timer_A0_ISR(void) { static unsigned char txBitCnt = 10; TACCR0 += UART_TBIT; // Add Offset to CCRx if (txBitCnt == 0) { // All bits TXed? TACCTL0 &= ~CCIE; // All bits TXed, disable interrupt txBitCnt = 10; // Re-load bit counter } else { if (txData & 0x01) { TACCTL0 &= ~OUTMOD2; // TX Mark '1' } else { TACCTL0 |= OUTMOD2; // TX Space '0' } txData >>= 1; txBitCnt--; } } // Switch interrupt service routine #pragma vector=PORT1_VECTOR __interrupt void Port_1(void) { randnum = rand() % 10; // random number 0 to 9 // Not very random, however, adequate for // this project. msgflag = 1; // message flag P1IFG &= ~BUTTON; // reset interrupt flag _bic_SR_register_on_exit(LPM0_bits); } //------------------------------------------------------------------------------
  • Create New...