Popular Content

Showing most liked content since 05/20/2017 in all areas

  1. 4 likes
    Now here's a set of fancy booster packs! It's a fully integrated automotive radar. http://www.ti.com/lsds/ti/sensing-products/mmwave-sensors/awr/awr-tools-software.page#tools Those rectangles on the right with wiggly traces to the IC are the radar antenna. RF magic! The "CAUTION HOT SURFACE" warning label also promises excitement. Too bad they will cost $299 according to the press release. Posting in the ARM sub-forum as the radar IC features an R4F ARM core. Though the booster packs probably work with beefier MSP430 LaunchPads too. Edit: Here's the mmWave landing page. The AWR also has the non-automotive sibling IWR, including similar booster packs. http://www.ti.com/lsds/ti/sensing-products/mmwave-sensors/mmwave-overview.page
  2. 4 likes
    Came across this while browsing. MSP430 Analog Gauge Clock
  3. 2 likes
    MISO should be connected with MISO, MOSI with MOSI, not crossed. MISO means Master In Slave Out, and MOSI means Master Out Slave In. Master & slave are always the same, no crossing is needed.
  4. 2 likes
    SIMPL = Serial Interpreted Minimal Programming Language Hi, It's been about a year since I talked about SIMPL - a tiny language that allows you basic control of a microcontroller using serial commands. In the 6 months I have coded it up in MSP430 assembly language to make it super compact - and fast - with high level commands taking about 1uS to execute on the virtual machine interpreter. SIMPL is based on a jump table - so for any single, printable ascii character, the jump table will act on it and execute whatever function you choose to write. This technique gives amazing flexibility, and for under 1K of code it can offer a very powerful user interface to your latest MSP430 project. One example is using the jump table to interpret commands from a text file to control a CNC mill or drill - or even a 3D printer. The core routines can be applied to any MSP430 - you just have to change the initialisation routines to suit the DCO, GPIO and UART of the specific microcontroller Just this week, I have got the looping to work, so you can now do things like send square waves to port pins for flashing LEDs and creating musical tones. With the standard Launchpad (MSP430GR2553) clocked at 16MHz you can send a 1uS pulse to a port pin - just by typing hl (shorthand for high, low) at the serial terminal. SIMPL is coded up in just 872 bytes of program memory - and can handle up to 96 separate commands. Commands can be sent to the device from a text file - using teraterm or similar - or just typed manually at the keyboard. I have put the latest code (some recent changes) on this github gist https://gist.github.com/monsonite/6483a32404c1c53cd8027dd6f9dcea6e This is a work in progress - and there are still a few bugs - but the basics seem to work OK. regards Ken Here's some more info about the various routines that make up the kernel textRead 33 Instructions 90 bytes Receive characters from the serial uart and place them into a buffer in RAM. Two modes of operation are possible, immediate mode, where the characters are executed as instructions directly after a carriage return line feed is received, and compile mode, where the character sequences are preceded by a colon and stored in pre-calculated command buffers in RAM. number 16 instructions 42 bytes Number interprets sequences of consecutive digits as a 16-bit integer number and places the value in the register that is the top entry of the stack. next 5 instructions 12 bytes Next is the routine that all commands return the program flow back to once they have executed. It fetches the next character instruction from the RAM buffer and through a jump table technique passes program control to the code body that performs the task associated with that instruction. The jump table is used to direct the character to the areas of code that will treat them correctly - for example on encountering a numerical digit, program control is passed to the number routine, whilst for upper case alphabetical characters, program control is passed to a routine that handles these separately. jump_table 96 instructions 192 bytes Primitives 72 instructions 166 bytes SIMPL uses a collection of 32 instruction primitives from which other instructions can be synthesised. The code body of these primitives is some 100 instructions or so. Upper (called alpha in V1) 10 instructions 26 bytes Upper handles the capital letters - as these are user commands, and the user is able to write and store in RAM certain functionality based on these characters. When a capital letter is encountered in the instruction buffer, Upper directs control to the correct command buffer. Lower 86 bytes Lower is an area of program that interprets the lower case characters and provides a higher level of program complexity than is achievable form the primitives alone. printnum 30 instructions 106 bytes This takes a 16 bit integer number from the stack and prints a string of ascii digit characters to the terminal. Uart Routines 13 instructions 41 bytes Low level communication with the uart is by way of the get_c and put_c routines Initialisation 19 instructions 90 bytes Here the hardware such as the oscillator, GPIO and uart are initialised for correct operation. This is code specific to whichever microcontroller has been chosen Interpreter 4 instructions 16 bytes This is the main routine that runs the SIMPL interpreter combining textRead, next, number and Upper. Here's the code - as it stands. Code window has mess up the formatting - but it should still cut and paste ;------------------------------------------------------------------------------- ; SIMPL - a very small Forth Inspired Extensible Language ; Implementing the Initialisation, TextTead, TextEval and UART routines in MSP430 assembly language ; ; A Forth-Like Language in under 1024 bytes ; Ken Boak May 22nd/23rd 2017 ; Loops, I/O, Strings and Delays added ; This version 872 bytes ; Instructions take about 1uS cycle time - so about 1/16th of clockspeed ;------------------------------------------------------------------------------- .cdecls C,LIST,"msp430.h" ; Include device header file ;------------------------------------------------------------------------------- .def RESET ; Export program entry-point to ; make it known to linker. ;------------------------------------------------------------------------------- ; Variables ;------------------------------------------------------------------------------- .sect "vars" .bss parray, 256 .bss x, 2 .bss name, 2 ;------------------------------------------------------------------------------- ; Using the register model of CH Ting's Direct Thread Model of MSP430 eForth ; CPU registers ; Register Usage ; R0 MSP430 PC Program Counter ; R1 MSP430 SP Stack Pointer ; R2 MSP430 SR Status Register tos .equ R4 stack .equ R5 ip .equ R6 temp0 .equ R7 ; loop start temp1 .equ R8 ; loop counter k temp2 .equ R9 ; millisecond delay temp3 .equ R10 ; microsecond delay temp4 .equ R11 instr .equ R12 temp5 .equ R13 temp6 .equ R14 ; temp7 .equ R15 ; Return from alpha next IP ;------------------------------------------------------------------------------- ; Macros pops .macro ;DROP mov.w @stack +, tos .endm pushs .macro ;DUP decd.w stack mov.w tos, 0(stack) .endm; ; Constants $NEXT .macro jmp next ; mov @ip+, pc ; fetch code address into PC .endm $NEST .macro .align 2 call #DOLST ; fetch code address into PC, W = PFA .endm $CONST .macro .align 2 call #DOCON ; fetch code address into PC, W = PFA .endm ;------------------------------------------------------------------------------ ;; Assembler constants COMPO .equ 040H ;lexicon compile only bit IMEDD .equ 080H ;lexicon immediate bit MASKK .equ 07F1FH ;lexicon bit mask CELLL .equ 2 ;size of a cell BASEE .equ 10 ;default radix VOCSS .equ 8 ;depth of vocabulary stack BKSPP .equ 8 ;backspace LF .equ 10 ;line feed CRR .equ 13 ;carriage return ERR .equ 27 ;error escape TIC .equ 39 ;tick CALLL .equ 012B0H ;NOP CALL opcodes UPP .equ 200H DPP .equ 220H SPP .equ 378H ;data stack TIBB .equ 380H ;terminal input buffer RPP .equ 3F8H ;return stacl CODEE .equ 0C000H ;code dictionary COLDD .equ 0FFFEH ;cold start vector EM .equ 0FFFFH ;top of memory ;------------------------------------------------------------------------------- .text ; Assemble into program memory. .retain ; Override ELF conditional linking ; and retain current section. .retainrefs ; And retain any sections that have ; references to current section. ;------------------------------------------------------------------------------- ; This implements the SIMPL interpreter is MSP430 assembly Language ;------------------------------------------------------------------------------- ; textRead ; ------------------------------------------------------------------------------ ; Get a character from the UART and store it in the input buffer starting at 0x0200 ; Register Usage ; The input buffer - start is at 0x0200, which is pointed to by R14 ; R11 is a counter to ensure that we don't exceed 64 characters in input buffer ; R12 receives the character from the uart_get_c routine and puts in the buffer, pointed to by R14 ; R14 is the current character position in the input buffer ; 33 instructions textRead: MOV.W #0x0200,R14 ; R14 = start of input buffer in RAM CLR.B R11 ; i = 0 getChar: CALL #uart_getc ; char ch = uart_getc() CMP.B #0x000d,R12 ; is it carriage return? 0d JEQ textEnd CMP.B #0x000a,R12 ; Is it newline? 0a JEQ textEnd CMP.B #0x0020,R12 ; if (ch >= ' ' && ch <= '~') JLO nonValid CMP.B #0x007f,R12 JHS nonValid CMP.B #0x003A,R12 ; is it colon? 3A JNE notColon colon: ; If the input character is a colon CALL #uart_getc ; get the next character - which is the NAME MOV.B R12,R13 ; move the 1st character after the colon to "name" variable in R13 times_32: SUB.B #0x0041,R13 ; Calculate the destination address - subtract 65 to remove offset of letter A ADD.W R13,R13 ; Double R13 ; multiply by 2 ADD.W R13,R13 ; Double R13 ; multiply by 4 ADD.W R13,R13 ; Double R13 ; multiply by 8 ADD.W R13,R13 ; Double R13 ; multiply by 16 ADD.W R13,R13 ; Double R13 ; multiply by 32 ADD.W R13,R14 ; Add (32*R13) to the index pointer R14 ADD.W #0x020,R14 ; Add to array pointer 0x0220 MOV.B R12,0x0000(R14) ; Store character at RAM buffer indexed by R14 ; R14 now contains the destination address JMP incPointer notColon: INC.W R14 ; Increment buffer pointer MOV.B R12,0xffff(R14) ; Store character at RAM buffer indexed by R14 incPointer: INC.B R11 ; Increment the input buffer pointer i++; nonValid: CMP.B #0x003f,R11 ; If input pointer <64 loop back to start JLO getChar ; loop back and get next character textEnd: mov.b #0x00,0x0000(R14) ; Put a null terminating (0x80) zero on the end of the buffer ; MOV.B R11,0x0000(R14) ; Put a null terminating (0x80) zero on the end of the buffer RET ;------------------------------------------------------------------------------------------------------------------- ; We now come onto the textEval - where based on the value of the character we perform some action routine ; But first we need to determine whether the characers form part of a number - and these must be decoded separately ; and put on the stack ;------------------------------------------------------------------------------------------------------------------- ; Register Usage ; ip - instruction pointer to the current character in the input buffer ; R12 is the accumulator for the number - then stored in location #0x380 ; R13 Temporary - use in x10 multipication ; R14 ; 16 Instructions number: SUB.W #0x0030,R12 ; subtract 0x30 to get a decimal number number1: CMP.B #0x0030,0x0000(ip) ; >= '0' Is the next digit a number JLO endNumber ; break CMP.B #0x003a,0x0000(ip) ; <= '9' JHS endNumber ; break times_10: ; This multipies R12 by 10 ADDC.W R12,R12 ; R12 = 2 * R12 MOV.W R12,R13 ; R13 = 2 * R12 ADDC.W R12,R12 ; R12 = 4 * R12 ADDC.W R12,R12 ; R12 = 8 x R12 ADDC.W R13,R12 ; R12 = 10 x R12 MOV.B @ip+,R14 ; Increment the instruction pointer fetching the next digit SUB.W #0x0030,R14 ADD.W R14, R12 ; Add in the next digit JMP number1 ; process the next digit endNumber: MOV.W R12, tos ; Put in tos - the top of stack JMP next ; process the next character ; Character is either a primitive or an alpha - so form CALL address ; Restore R14 to start of RAM buffer ; Get the current character location ; If it's a primitive between 0x20 and 0x3F - point to a look-up table and fetch it's code segment address ; If its an Alpha, or character >0x40 calculate it's code address from (char - 65)x32 ; Character is in R13 so calculate the destination address ; ------------------------------------------------------------------------------------------------------------------- ; next fetches the next ascii character instruction from memory, decodes it into a jump address and executes the code ; found at that code address ; Each executed word jumps back to next ; Numbers are treated differenty - they are enummerated and put onto the stack by the number routine ; Now we need to decode the instructions using a jump table ; Jump table uses 2 bytes per instruction - so 2 x 96 = 192 bytes next: MOV.B @ip+,R12 ; Get the next character from the instruction memory MOV.W R12,R13 ; Copy into R13 - as needed to decode Jump Address SUB.w #0x0020,R13 ; subtract 32 to remove offset of space ADD.w R13,R13 ; double it for word address add.w R13,pc ; jump to table entry tabstart: jmp space ; SP jmp store ; ! jmp dup ; " jmp lit ; # jmp swap ; $ jmp over ; % jmp and ; & jmp drop ; ' jmp left_par ; ( jmp right_par ; ) jmp mult ; * jmp add ; + jmp push ; , jmp sub ; - jmp pop ; . jmp div ; / jmp number ; 0 jmp number ; 1 jmp number ; 2 jmp number ; 3 jmp number ; 4 jmp number ; 5 jmp number ; 6 jmp number ; 7 jmp number ; 8 jmp number ; 9 jmp colon ; : jmp semi ; ; jmp less ; < jmp equal ; = jmp greater ; > jmp query ; ? jmp fetch ; @ jmp alpha ; A jmp alpha ; B jmp alpha ; C jmp alpha ; D jmp alpha ; E jmp alpha ; F jmp alpha ; G jmp alpha ; H jmp alpha ; I jmp alpha ; J jmp alpha ; K jmp alpha ; L jmp alpha ; M jmp alpha ; N jmp alpha ; O jmp alpha ; P jmp alpha ; Q jmp alpha ; R jmp alpha ; S jmp alpha ; T jmp alpha ; U jmp alpha ; V jmp alpha ; W jmp alpha ; X jmp alpha ; Y jmp alpha ; Z jmp square_left ; [ jmp f_slash ; \ ; jmp square_right ; ] jmp xor ; ^ jmp underscore ; _ jmp tick ; ` jmp lower_a ; a jmp lower_b ; b jmp lower_c ; c jmp lower_d ; d jmp lower_e ; e jmp lower_f ; f jmp lower_g ; g jmp lower_h ; h jmp lower_i ; i jmp lower_j ; j jmp lower_k ; k jmp lower_l ; l jmp lower_m ; m jmp lower_n ; n jmp lower_o ; o jmp lower_p ; p jmp lower_q ; q jmp lower_r ; r jmp lower_s ; s jmp lower_t ; t jmp lower_u ; u jmp lower_v ; v jmp lower_w ; w jmp lower_x ; x jmp lower_y ; y jmp lower_z ; z jmp curly_left ; { jmp or ; | jmp curly_right ; } jmp inv ; ~ jmp delete ; del jmp textEval_end ; 0x80 is used as null terminator ;----------------------------------------------------------------------------------------- ; Handle the alpha and lower case chars alpha: SUB.B #0x0041,R12 ; subtract 65 to remove offset of letter A from original character MOV.W R12,R13 ; get it into R13 for multiplying ADD.W R13,R13 ; Double R13 ; multiply by 2 ADD.W R13,R13 ; Double R13 ; multiply by 4 ADD.W R13,R13 ; Double R13 ; multiply by 8 ADD.W R13,R13 ; Double R13 ; multiply by 16 ADD.W R13,R13 ; Double R13 ; multiply by 32 ADD.W #0x220,R13 ; Add (32*R13) to the index pointer R14 MOV.W ip,R15 ; Save the current ip on the return stack R15 ; R13 now contains the jump address for the alpha code MOV.W R13,ip ; instruction pointer JMP next ; process the next character ;----------------------------------------------------------------------------------------- ; Handle the primitive instructions space: pushs ; Move a 2nd number onto the stack $NEXT store: mov.w @stack +, 0(tos) pops $NEXT dup: pushs $NEXT lit: $NEXT swap: mov.w tos, temp0 mov.w @stack, tos mov.w temp0,0( stack) $NEXT over: mov.w tos, temp0 mov.w @stack, tos mov.w temp0,0( stack) $NEXT and: and @stack +, tos $NEXT drop: pops $NEXT left_par: ; code enters here on getting a left parenthesis MOV.W tos,R8 ; save tos to R8 (R8 is the loop counter k) MOV.W ip,R7 ; loop-start = ip the current instruction pointer at start of loop JMP next ; get the next character and execute it right_par: ; code enters here if instruction it's a right parenthesis ; TST.W R8 ; is loop counter zero ; JEQ next ; terminate loop DEC.W R8 ; decrement loop counter R8 JEQ next ; terminate loop MOV.W R7,ip ; set instruction pointer to the start of the loop JMP next ; go around loop again until loop counter = 0 mult: $NEXT add: add @stack +, tos $NEXT push: $NEXT sub: sub @stack +, tos ; jmp NEGAT NEGAT: inv tos inc tos $NEXT pop: jmp printNum ; go to decimal number print $NEXT div: $NEXT semi: ; On encountering a semicolon return program control to the next character in the input buffer MOV.W R15,ip ; restore the ip $NEXT query: $NEXT fetch: mov.w @tos, tos $NEXT square_right: f_slash: square_left: curly_right: curly_left: underscore: ; Print the enclosed text print_start: MOV.B @ip+,R12 ; Get the next character from the instruction memory CMP.B #0x005f,R12 ; is it an underscore jeq print_end CALL #uart_putc ; send it to uart jmp print_start print_end call #crlf ; line feed at end of text string $NEXT tick: ; tick allows access to the loop counter MOV.W R8,tos $NEXT delete: $NEXT or: bis @stack +, tos $NEXT xor: xor @stack +, tos $NEXT inv: inv tos $NEXT less: cmp @stack +, tos jz FALSE jge TRUE jmp FALSE equal: xor @stack +, tos jnz FALSE jmp TRUE greater: cmp @stack +, tos jge FALSE jmp TRUE FALSE: clr tos $NEXT TRUE: mov #0x01, tos $NEXT ;------------------------------------------------------------------------------------------------ ;lower case routines lower_a: $NEXT lower_b: $NEXT lower_c: $NEXT lower_d: $NEXT lower_e: $NEXT lower_f: $NEXT lower_g: $NEXT lower_h: MOV.B #0x0001,&P1OUT ; P1OUT = BIT0 LED1 on $NEXT lower_i: $NEXT lower_j: $NEXT lower_k: ; k allows access to the loop counter variable stored in R8 MOV.W R8,tos $NEXT lower_l: MOV.B #0x0000,&P1OUT ; P1OUT = BIT0 LED1 off $NEXT lower_m: ; millisecond delay MOV.W tos,R10 mS_loop: mov.w #5232,R9 ; 5232 gives 1mS at 16MHz uS3_loop: DEC.W R9 JNE uS3_loop DEC.W R10 JNE mS_loop $NEXT lower_n: $NEXT lower_o: $NEXT lower_p: JMP printNum $NEXT lower_q: $NEXT lower_r: $NEXT lower_s: $NEXT lower_t: $NEXT lower_u: ; 3 microsecond deelay MOV.W tos,R10 uS_loop: DEC.W R10 JNE uS_loop $NEXT lower_v: $NEXT lower_w: $NEXT lower_x: $NEXT lower_y: $NEXT lower_z: $NEXT ;------------------------------------------------------------------------------------------------ ; User Routines ;------------------------------------------------------------------------------------------------- printNum: ; Take the 16 bit value in R4 stack register and print to terminal as an integer ; do by repeated subtraction of powers of 10 ; Uses R10,11,12,13 ;------------------------------------------------------------------------------------------------- MOV.W #10000,R10 ; R10 used as the decimation register ; CLR.W R12 ; use R12 as a counter CLR.W R11 ; Use R11 as scratch CLR.W R13 MOV.W tos,R12 ; copy the top of stack into R12 CLRC ; clear the carry sub10K: SUB.W R10,R12 JLO end10K add10K: ADD.B #1,R11 ; increments the digit count add_zero: ADD.W R10,R13 ; R13 increases by the decimal value each time JMP sub10K end10K: ADD.B #0x30,R11 ; make it a number MOV.W R11,R12 CALL #uart_putc ; output character SUB.W R13,tos ; Decrement the stack count by n x 10 CLR.W R11 ; Use R11 as scratch CLR.W R13 MOV.W tos,R12 decimate: CMP.W #10000,R10 JEQ use1K CMP.W #1000,R10 JEQ use100 CMP.W #100,R10 JEQ use10 CMP.W #10,R10 JEQ use1 newline: MOV.W #0x0A, R12 CALL #uart_putc ; output CR MOV.W #0x0D, R12 CALL #uart_putc ; output LF JMP next use1K: MOV.W #1000,R10 JMP sub10K use100: MOV.W #100,R10 JMP sub10K use10: MOV.W #10,R10 JMP sub10K use1: MOV.W #1,R10 JMP sub10K ;------------------------------------------------------------------------------------------------- ;------------------------------------------------------------------------------------------------------------------- ; Uses R12 to send receive chars via the UART at 115200 baud. uart_getc: BIT.B #1,&IFG2 ; while (!(IFG2&UCA0RXIFG)) // USCI_A0 RX buffer ready? JEQ (uart_getc) MOV.B &UCA0RXBUF,R12 ; return UCA0RXBUF; RET uart_putc: BIT.B #2,&IFG2 ; while (!(IFG2&UCA0TXIFG)) // USCI_A0 TX buffer ready? JEQ (uart_putc) MOV.B R12,&UCA0TXBUF ; UCA0TXBUF = c; // TX RET crlf: MOV.W #0x0A, R12 CALL #uart_putc ; output CR MOV.W #0x0D, R12 CALL #uart_putc ; output LF RET ;------------------------------------------------------------------------------- ; Main loop here ;------------------------------------------------------------------------------- main: ;------------------------------------------------------------------------------- RESET: ; mov.w #03E0h,SP ; Initialize stackpointer mov #RPP, SP ; set up stack mov #SPP, stack clr tos StopWDT: mov.w #WDTPW|WDTHOLD,&WDTCTL ; Stop watchdog timer WDTCTL = WDTPW + WDTHOLD; Stop WDT OSC_GPIO_init: ; Run the CPU at full 16MHz with 11500baud UART MOV.B &CALBC1_16MHZ,&BCSCTL1 ;BCSCTL1 = CALBC1_16MHZ; Set DCO MOV.B &CALDCO_16MHZ,&DCOCTL ;DCOCTL = CALDCO_16MHZ; SetupP1: bis.b #041h,&P1DIR ;P1.0 P1.6 output as P1.0 and P1.6 are the red+green LEDs MOV.B #0x0000,&P1OUT ;P1OUT = BIT0 + BIT6; // All LEDs off uart_init: MOV.B #0x0006,&P1SEL ;Initialise the UART for 115200 baud MOV.B #0x0006,&P1SEL2 ;P1SEL2 = RXD + TXD; BIS.B #0x0080,&UCA0CTL1 ;UCA0CTL1 |= UCSSEL_2// SMCLK MOV.B #0x008A,&UCA0BR0 ;UCA0BR0 = 138 // 16MHz 115200 CLR.B &UCA0BR1 ;UCA0BR1 = 0 // 16MHz 115200 MOV.B #2,&UCA0MCTL ;UCA0MCTL = UCBRS0 // Modulation UCBRSx = 1 BIC.B #1,&UCA0CTL1 ;UCA0CTL1 &= ~UCSWRST Initialize USCI state machine MOV.W #0x4F, R12 CALL #uart_putc ; output "O" MOV.W #0x4B, R12 CALL #uart_putc ; output "K" ; Print OK ;------------------------------------------------------------------------------- interpreter: call #textRead MOV.W #0x0200,ip ; set ip (instruction pointer) - to start of input buffer in RAM at address 0x0200 jmp next ; get the next instruction textEval_end: jmp interpreter ; loop around ; Stack Pointer definition ;------------------------------------------------------------------------------- .global __STACK_END .sect .stack ;------------------------------------------------------------------------------- ; Interrupt Vectors ;------------------------------------------------------------------------------- .sect ".reset" ; MSP430 RESET Vector .short RESET .end
  5. 2 likes
    Hi, for the projects I need to access from multiple places (and needing some privacy) I've configured a small git server and put gogit/gogs *) on top of it. Because the core is git, I can use it from command line and gogit gives me the possibility to use it in a way similar to github and (the reason I use it) allows me to define "virtual users" - I can allow other people to access the private repositories without sharing my (main) credentials. I have luck with a good hosting offering all needed tools. Cheers, Liviu *) I suppose any "interface" will do the same, I've used gogs because I found a tutorial (in German) about the installation on my server.
  6. 1 like
    Yes, it will be in the next release. Unfortunately this is taking a lot longer than anticipated due to the fact that we are making it compatible with both the new (msp430-elf-gcc and the old msp430-gcc).
  7. 1 like
    Yes, I've seen, I've read the wrong documentation. Should work without mode qualifiers.
  8. 1 like
    LE I've read the examples coming with PetitFS and they aren't using the mode specifier neither. No idea why it doesn't work for you.
  9. 1 like
    Hi, nice to see that making the connection properly bring it to work. Carefully reading the replies you receive may even accelerate the success. For your last problem - writing without writing - maybe you should open the file in the correct mode. In this case the mode should be FA_WRITE. Try to replace with rc = FatFs.open("T_WRITE.TXT", FA_WRITE); or rc = FatFs.open("T_WRITE.TXT", FA_WRITE | FA_READ); for read & write access.
  10. 1 like
    Have you tried with the last version of the library, mentioned on the https://hmario.home.xs4all.nl/arduino/LiquidCrystal_I2C/?
  11. 1 like
    TI Store Geek Week 2017! 10% off on selected items and free shipping! http://app.marketing.ti.com/e/es.aspx?s=441910513&e=123094&elq=3195d88a3376467490cb0607fdefe72c Regards Amaze1
  12. 1 like
    As long you receive "can't open port" messages, I see two possibilities: - wrong port - bad hardware.
  13. 1 like
  14. 1 like
    Hi everyone, I have idea to use msp430 and hacked atx power supply as a car battery charger. Simply msp430 will be used to control of charge process, different charging current, time, precharging and swichable load for accurate voltage measurement will be available. Done: * hacked atx to 17V * enclosure * schematics * pcb * functional code To do: * firmware development If anyone have some suggestions fell free to post within this topic, I'll be grateful. Simple description of operation: At first voltage measurement is initiated, user set type of car battery, capacity and charge strategy. While charging is started PWM signal control P-MOSFET to set correct current, feedback is taken from 5mR shunt resistor trough RC low-pass filter and software implementation of 3 order Chebyshev LP filter. Every 5 minutes charge process stops, load resistor is applied and voltage reading is taken. During charge process user can see actual voltage, current, elapsed time and estimated period to end of charging. If battery will be accidentally disconnected mcu stops charging process. [uPDATE] 22.12.2012 ====================================================== Results. ATX2CHARGER is now working, I've successfully charged some car batteries. In near future I need to finish firmware, add rest of options etc. Tomorrow I'll add attachments (sorce of firmware and gerbers). Final schematics: PCB: Tests of working unit: All media: http://imageshack.us/g/1/9930724/ http://imageshack.us/g/1/9930688/ main.c: /*==================================================================== * * ATX2CHARGER v1.0 * 2012 by blankfield <blank0field@gmail.com> * MSP430G2553 @ 16MHz, 3,3V * ===================================================================*/ /*==================================================================== * * headers and includes * ===================================================================*/ #include <msp430.h> #include <ti/mcu/msp430/csl/CSL.h> #include <stdio.h> #include <string.h> #include "msp430g2553.h" #include "main.h" #include "LCD2x16.h" /*==================================================================== * * constants and definitions * ===================================================================*/ //charge indicator animation const char bat0[8] = {0x0A, 0x1F, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1F}; const char bat1[8] = {0x0A, 0x1F, 0x11, 0x11, 0x11, 0x11, 0x1F, 0x1F}; const char bat2[8] = {0x0A, 0x1F, 0x11, 0x11, 0x11, 0x1F, 0x1F, 0x1F}; const char bat3[8] = {0x0A, 0x1F, 0x11, 0x11, 0x1F, 0x1F, 0x1F, 0x1F}; const char bat4[8] = {0x0A, 0x1F, 0x11, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F}; const char bat5[8] = {0x0A, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F}; #define SWSTART BIT7 //P2.7 - START #define SWF1 BIT7 //P1.7 - F1 #define SWF2 BIT6 //P1.6 - F2 #define FIRNtap 15 //fir lp filter number of tap #define Vref (float)3.3 #define ADCRES (float)1023 #define R7resistor (float)4650 #define R9resistor (float)1005 #define R15resistor (float)0.005 #define Uconstant (float)((Vref/ADCRES)*((R7resistor+R9resistor)/R9resistor)) #define Iconstant (float)((Vref/ADCRES)/(R15resistor)) enum enumdisplay_menu {startup, measure_acc, settings, chargeing_params, chargeing_time, summary}; enum enumcharge_type {emergency, normal, mainterance_free}; enum enumaccu_voltage {U6V, U12V}; enum enumstate {idle, charge, discharge}; #pragma DATA_SECTION(ee_charge_type, ".mydata"); #pragma DATA_SECTION(ee_accu_capacity, ".mydata"); #pragma DATA_SECTION(ee_accu_voltage, ".mydata"); #pragma DATA_ALIGN(ee_charge_type, 1); #pragma DATA_ALIGN(ee_accu_capacity, 1) #pragma DATA_ALIGN(ee_accu_voltage, 1); /*==================================================================== * * variables * ===================================================================*/ //FLASH "EEPROM" VALUES unsigned char ee_charge_type; unsigned char ee_accu_capacity; unsigned char ee_accu_voltage; struct timeformat { char hours; char minutes; char seconds; }time; int time_prescale=0; int measurments[4]; float measured_charge_current = 0; float measured_charge_voltage = 0; float measured_discharge_current = 0; float measured_discharge_voltage = 0; float measured_idle_current = 0; float measured_idle_voltage = 0; float Iavg = 0; float Imax = 0; float Ucellmax = 2.5; float Ucelloptimum = 2.4; char accu_capacity = 75; char accu_voltage = U12V; char charge_type = normal; //char charge_time = 0; char charge_progress = 0; char elapsed_1s = false; char tempstring[20]; float DCV[10]; char display_level = startup; char state = idle; /*==================================================================== * * main() * ===================================================================*/ int main(int argc, char *argv[]){ CSL_init();// Activate Grace-generated configuration __delay_cycles(5000); init_mcu(); _delay_cycles(1000000); LCD2x16_Initialize(); __delay_cycles(5000); LCD2x16_WriteCommand(0x01); __delay_cycles(5000); ADC10CTL0 |= ENC;//Start ADC TA1CCR1 = 0; while(1){ control(); if (elapsed_1s){ sprintf(tempstring,"%1.2f;%1.2f;%1.2f;%1.2f;%1.2f;%1.2f;", measured_idle_voltage,measured_idle_current, measured_charge_voltage,measured_charge_current, measured_discharge_voltage,measured_discharge_current); int i; for (i=0; i<sizeof(tempstring); i++) { while (!(IFG2 & UCA0TXIFG)); UCA0TXBUF = tempstring[i]; } elapsed_1s=false; } switch(display_level){ case startup: menu_redraw(); __delay_cycles(25000000); display_level = measure_acc; menu_redraw(); break; case measure_acc: menu_redraw(); if (!(P2IN & SWSTART)) { beep_sound(); display_level=settings; menu_redraw(); } if (!(P1IN & SWF1)) { beep_sound(); if (accu_voltage == U12V) accu_voltage = U6V; else accu_voltage = U12V; menu_redraw(); } break; case settings: if (!(P2IN & SWSTART) && true) { beep_sound(); time.seconds=0; time.minutes=0; time.hours=0; Iavg=0; display_level = chargeing_params; state = charge; menu_redraw(); } if (!(P1IN & SWF1)) { beep_sound(); accu_capacity += 5; if (accu_capacity > 200) accu_capacity = 5; menu_redraw(); } if (!(P1IN & SWF2)) { beep_sound(); charge_type++; if (charge_type>=3) charge_type=0; menu_redraw(); } break; case chargeing_params: if (!(P2IN & SWSTART)) { beep_sound(); display_level=summary; state = idle; menu_redraw(); } if (!(P1IN & SWF1)) { beep_sound(); display_level=chargeing_time; menu_redraw(); } break; case chargeing_time: if (!(P2IN & SWSTART)) { beep_sound(); display_level=summary; state = idle; menu_redraw(); } if (!(P1IN & SWF1)) { beep_sound(); display_level=chargeing_time; menu_redraw(); } break; case summary: if (!(P2IN & SWSTART)) { beep_sound(); display_level=measure_acc; menu_redraw(); } break; } } } /*==================================================================== * * menu_redraw() * ===================================================================*/ void menu_redraw(void){ LCD2x16_GoTo(0,0); switch(display_level){ case startup: LCD2x16_WriteText("ATX2CHARGER v1.0"); LCD2x16_GoTo(0,1); LCD2x16_WriteText(" by blankfield"); break; case measure_acc: if (measured_idle_voltage <=1){ LCD2x16_WriteText("Check battery, "); LCD2x16_GoTo(0,1); sprintf(tempstring,"%01.2fV is too low ",measured_idle_voltage); LCD2x16_WriteText(tempstring); } else{ sprintf(tempstring,"Battery U=%02.2fV ",measured_idle_voltage); LCD2x16_WriteText(tempstring); LCD2x16_GoTo(0,1); //sprintf(tempstring,"P=%01.0f I= %02.2fA ", TA1CCR1*0.05, measured_idle_current); sprintf(tempstring,"Type F1:%02.0dV ",(accu_voltage*6)+6); LCD2x16_WriteText(tempstring); } break; case settings: sprintf(tempstring,"Set cap F1:%03.0dAh ",accu_capacity); LCD2x16_WriteText(tempstring); LCD2x16_GoTo(0,1); if (charge_type==normal) LCD2x16_WriteText("F2: standard "); if (charge_type==mainterance_free) LCD2x16_WriteText("F2: mainter.free"); if (charge_type==emergency) LCD2x16_WriteText("F2: emerg.charg."); break; case chargeing_params: sprintf(tempstring,"U=%02.1fV I=%02.1fA", measured_charge_voltage, measured_charge_current); LCD2x16_WriteText(tempstring); LCD2x16_GoTo(0,1); sprintf(tempstring,"U=%02.1fV I=%02.1fA", measured_discharge_voltage, measured_discharge_current); break; case chargeing_time: sprintf(tempstring,"Elapsed %2.0f:%2.0f:%2.0f", time.hours, time.minutes, time.seconds); LCD2x16_WriteText(tempstring); LCD2x16_GoTo(0,1); sprintf(tempstring,"Iavg=%2.2f ", Iavg); LCD2x16_WriteText(tempstring); break; case summary: LCD2x16_WriteText("Finished! "); LCD2x16_GoTo(0,1); sprintf(tempstring,"%2.0f:%2.0f:%2.0f @ %2.2f", time.hours, time.minutes, time.seconds, Iavg); LCD2x16_WriteText(tempstring); break; } } /*==================================================================== * * control() * ===================================================================*/ void control(void){ switch (state){ case idle: TA1CCR1=0; TA1CCR2=0; break; case charge: TA1CCR2=0; if ((measured_charge_voltage < (Ucelloptimum*3*(accu_voltage+1))) && (measured_charge_current < (accu_capacity/5/(charge_type+1))) && (TA1CCR1<1999)){ TA1CCR1++; } if (((measured_charge_voltage > (Ucelloptimum*3*(accu_voltage+1))) || (measured_charge_current > (accu_capacity/5/(charge_type+1)))) && (TA1CCR1>1)){ TA1CCR1--; } if (TA1CCR1 <=100 && measured_charge_voltage >= (Ucelloptimum*3*(accu_voltage+1))){ state = idle; display_level = summary; beep_sound(); } break; case discharge: TA1CCR1=0; TA1CCR2=1000; break; } } /*==================================================================== * * init_mcu() * ===================================================================*/ void init_mcu(void){ WDTCTL = WDTPW + WDTHOLD; char name[18]="AT+NAMEATX2CHARGER"; int i; for (i=0; i<18; i++) { while (!(IFG2 & UCA0TXIFG)); UCA0TXBUF = name[i]; } } /*==================================================================== * * measure() * interrupts from ADC * ===================================================================*/ void measure(void){ time_prescale++; if (time_prescale==999){ elapsed_1s=true; time.seconds++; //increase every 1s if(time.seconds==60){ time.seconds=0; time.minutes++; if(time.minutes==60){ time.minutes=0; time.hours++; } } } switch (state){ case idle: measured_idle_current = measurments[3]*Iconstant; measured_idle_voltage = measurments[0]*Uconstant; break; case charge: measured_charge_current = measurments[3]*Iconstant; Iavg = (Iavg + measured_charge_current)/2; measured_charge_voltage = measurments[0]*Uconstant; break; case discharge: measured_discharge_current = measurments[3]*Iconstant; measured_discharge_voltage = measurments[0]*Uconstant; break; } return; } /*==================================================================== * * beep_sound() * ===================================================================*/ void beep_sound(void){ TA0CCR1 = 1000; __delay_cycles(500000); TA0CCR1 = 0; return; } /*==================================================================== * * fir() * ===================================================================== WinFilter version 0.8 http://www.winfilter.20m.com akundert@hotmail.com Filter type: Low Pass Filter model: Chebyshev Filter order: 3 Sampling Frequency: 1000 Hz Cut Frequency: 6.000000 Hz Pass band Ripple: 1.000000 dB Coefficents Quantization: float Z domain Zeros z = -1.000000 + j 0.000000 z = -1.000000 + j 0.000000 z = -1.000000 + j 0.000000 Z domain Poles z = 0.981540 + j -0.000000 z = 0.990073 + j -0.036073 z = 0.990073 + j 0.036073 ***************************************************************/ float fir(float NewSample) { float FIRCoef[FIRNtap] = { 0.06499156895458164900, 0.06567519555537033900, 0.06626048168634461600, 0.06674435292740793500, 0.06712913054423083600, 0.06742809591680600000, 0.06768722943723189100, 0.06816788995605341200, 0.06768722943723189100, 0.06742809591680600000, 0.06712913054423083600, 0.06674435292740793500, 0.06626048168634461600, 0.06567519555537033900, 0.06499156895458164900 }; static float x[FIRNtap]; //input samples float y=0; //output sample int n; //shift the old samples for(n=FIRNtap-1; n>0; n--) x[n] = x[n-1]; //Calculate the new output x[0] = NewSample; for(n=0; n<FIRNtap; n++) y += FIRCoef[n] * x[n]; return y; } /*==================================================================== * * flashEraseSegment(int FarPtr) * ===================================================================*/ void flashEraseSegment(int FarPtr){ int *Flash_ptr; // local Flash pointer Flash_ptr = (int *) FarPtr; // Initialize Flash pointer FCTL1 = FWKEY + ERASE; FCTL3 = FWKEY; *Flash_ptr = 0; // dummy write to start erase while (FCTL3 & BUSY ); FCTL1 = FWKEY; FCTL3 = FWKEY + LOCK; } /*==================================================================== * * saveSettings(void) * ===================================================================*/ void saveSettings(void){ flashEraseSegment((int) 0xC000); FCTL1 = FWKEY + WRT; FCTL3 = FWKEY; ee_charge_type = (char)charge_type; ee_accu_capacity = (char)accu_capacity; ee_accu_voltage = (char)accu_voltage; FCTL1 = FWKEY; FCTL3 = FWKEY + LOCK; } /*==================================================================== * * loadSettings(void) * ===================================================================*/ void loadSettings(void){ charge_type = (char)ee_charge_type; accu_capacity = (char)ee_accu_capacity; accu_voltage = (char)ee_accu_voltage; } main.h: #ifndef MAIN_H_ #define MAIN_H_ #define false 0 #define true 1 void menu_redraw(void); void control(void); void init_mcu(void); void buttons(void); void measure(void); void beep_sound(void); float fir(float NewSample); void flashEraseSegment(int FarPtr); void saveSettings(void); void loadSettings(void); #endif /* MAIN_H_ */ LCD2x16.c: // ----------------------------------------------------------------#include "LCD2x16.h"#include "msp430g2553.h"#define RS BIT3 // RS - P2.3 RW - GND#define EN BIT5 // EN - P2.5#define D4 BIT4 // D4 - P1.4#define D5 BIT5 // D5 - P1.5#define D6 BIT0 // D6 - P2.0#define D7 BIT1 // D7 - P2.1//Polish language characters//E6 B9 B3 EA F3 F1 9F 9C A5 BF CA C6 D1 A3 8C D3 AF 8F//? ? ? ? ? atx2charger-firmware.zip gerbers-mirror.zip gerbers.zip
  15. 1 like
    In the post I've linked above the solution was to replace the twi.c & twi_sw.c with new ones, found in the e2e forum. Have you also replaced them?
  16. 1 like
    As @@chicken mentioned make sure you have a ground connection between the 2 LaunchPads. Could you also post the 2 Sketch so that we can have a look at that as well?
  17. 1 like
    Hi @@brelliott18, There are some known problems with i2c on 2553 Launchpads, mentioned in various posts over this forum. One of them is mentioned in http://forum.43oh.com/topic/2641-i2c-lcd/page-2#entry75927; in this post is also a link to a solution http://e2e.ti.com/support/development_tools/code_composer_studio/f/81/p/529036/1924562#1924562 Have you already seen this posts? Have you tried the solutions presented in them? Regards, Liviu
  18. 1 like
    Edit 09.12.2016: I added Arial_16x24.h and Arial_24x40 (really a 24x36, but I had to keep a multiple of 8), digits only, created with GLCD Font Creator (I had to edit the result slightly manually). See images below. So I can confirm that adding any further fonts created with GLCD Font Creator works (I run it on Linux on wine BTW) and is only limited by how much fits into the SSD1306_OLED_5x8_11x16_16x24_24x36_fonts.zip
  19. 1 like
    Hi, Glad to hear it's working for you. Since the changed library seems to work (I've also updated the example and replaced the library in the post above), maybe Calin or a moderator can update the download on the first post of the topic. Liviu
  20. 1 like
    Try to locate (I suppose even Macs have a search program ) the PFatFs directory and delete it. Unzip and put the content of the changed library in place of it.
  21. 1 like
    I've changed the DIR with FSDIR in the PFatFs library; I'm attaching the changed library here. Just replace the one on your PC with the attached one. On my PC I've put it in ../energia-1.6.10E18/libraries/PFatFs/ You should probably change your sketches too. Regards, Liviu EDIT: updated the library (fixed the examples too). PFatFs.zip
  22. 1 like
    Hi, fount it. It seems, the DIR definition in energia-1.6.10E18/hardware/tools/msp430/msp430/include/msp430f5529.h /* USBCTL Control Bits */ #define DIR (0x0001) /* USB - Data Response Bit */ conflicts with the DIR in the energia-1.6.10E18/libraries/PFatFs/utility/pff.h: /* Directory object structure */ typedef struct { WORD index; /* Current read/write index number */ BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */ CLUST sclust; /* Table start cluster (0:Static table) */ CLUST clust; /* Current cluster */ DWORD sect; /* Current sector */ } DIR; No idea where it will be better to change to remove the conflict, but probably in the PFatFs. Regards, Liviu
  23. 1 like
    Hi, it seems the file energia-1.6.10E18/hardware/tools/msp430/msp430/include/msp430f5529.h has a problem in the USB definition part. I don't know exactly what for a problem, but I was able to compile the above mentioned sketch after commenting out the USB part in msp430f5529.h (between rows ~3430 and ~4227). Maybe it helps you. Regards, Liviu
  24. 1 like
    Hi, which board are you using? I've tested now the "PFatFsFileTest" (library) example and it compiles for the launchpads installed by default by Energia (+TivaC), except MSP-EXP430G5529LP. Regards, Liviu
  25. 1 like
    Hi Spineless, I think you should install it as a library. Liviu
  26. 1 like
    Not sure what you are trying to do.. but there is an example here: http://elm-chan.org/fsw/ff/pf/lseek.html
  27. 1 like
    Hi, I'm trying to use an SDCard as a datalogger. I can write to the card using the sample. I want to append the data and for that I'm using a 4 byte header in the file. It seems that when I want to update the header after a logging session all the data is missing from the file as well. What am I doing wrong: ... rc = FatFs.open("T_WRITE.TXT"); if (rc) die(rc); char buffer[4]; rc = FatFs.read(buffer, sizeof(buffer), &br); /* Read a chunk of file */ if (rc || !br) die(rc); /* Error or end of file */ for (uint16_t i = 0; i < br; i++){ fileIndex.myByte[i]=buffer[i]; } rc = FatFs.lseek(fileIndex.myLong+4); if (rc) die(rc); for (uint16_t i=0;i<20;i++) { // simulate write of data int val[4]; val[0]=random(2000); val[1]=random(2000); val[2]=random(2000); val[3]=random(2000); String reading; reading+=val[0]; reading+=" "; reading+=val[1]; reading+=" "; reading+=val[2]; reading+=" "; reading+=val[3]; reading+="\n\t"; char buf[reading.length()]; reading.toCharArray(buf, reading.length()); rc = FatFs.write(buf, reading.length(), &bw); // update index value fileIndex.myLong+=reading.length(); if (rc) break; } if (rc) die(rc); rc = FatFs.write(0, 0, &bw); //Finalize write if (rc) die(rc); //update fileindex rc=FatFs.lseek(0); rc = FatFs.write(fileIndex.myByte,4,&bw); if (rc) die(rc); rc = FatFs.write(0, 0, &bw); //Finalize write if (rc) die(rc); rc=FatFs.close(); if (rc) die(rc); Serial.println(); Serial.print("Test completed."); regards Bob