Jump to content
43oh

spirilis

Members
  • Content Count

    3,399
  • Joined

  • Last visited

  • Days Won

    146

Posts posted by spirilis

  1. Not what I would've expected but I see now it works.

     

    void setup()
    {
      // put your setup code here, to run once:
      pinMode(RED_LED, OUTPUT);
    }
    
    void loop()
    {
      // put your main code here, to run repeatedly:
      static int u = 1;
      digitalWrite(RED_LED, u);
      delay(500);
      u = !u;
    }
    Does, in fact, blink the LED.

     

     

    This is all totally off topic from the OP but who cares... ;)

    A common idiom I find myself doing to test serial access or whatever is:

    void loop() {
      static unsigned long i = 0;
    
      Serial.print("Number: ");
      Serial.println(i++);
      delay(250);
    }
    
  2. @@B@tto @@spirilis

    But at the top of loop(): "static byte u=1;"

    So "u" is assigned the value of "1" at the start of each iteration, no?

    No.  Because the "static" keyword is there, this only happens once, at the very beginning of program start.  This is what makes the "static" keyword special in the context of a function (in addition to the fact that it informs the compiler to allocate the variable outside the function's ephemeral stack space).

     

    Note that in the global context, i.e. outside of a function, "static" means something totally different.  Yay C!

  3. But then... what about "u=!u;" at the end of loop()?

    That's what's confusing me. Does "u" get "not" u or is it "1" each time loop() executes?

    u gets not'ted (1 to 0, 0 to 1) every time it executes.

     

    First time around, u = 1.

    Then u gets notted.

    Second time around, u = 0.

    Then u gets notted.

    Third time around, u = 1.

    etc and so forth

  4. void loop()
    {
    
      static byte u=1;
     
      for(int i=0;i<3;i++) {
        
      Wire.beginTransmission(8); // transmit to device #8
      Wire.write(i);
      Wire.write(u);              // sends one byte
      Wire.endTransmission();    // stop transmitting
     
      delay(1000);
     
      }
     
      u=!u;
     
    }
    That won't work.... Okay, maybe it will, but:

     

    You define and assign "u" a value of 1 at the top of "loop()", then negate its value at the bottom of the loop()... but it gets re-defined and assigned "1" at the start of the loop()... which repeats over and over. I.e. "u" will always have the value of "1" within loop().

     

    That will work, actually.  The "static" keyword when used inside a function tells the compiler to persist its value across subsequent executions of the function.  The variable then actually gets allocated within the bss/global space, rather than the function's stack (where it would get re-initialized every execution of loop()).  In this usage, the assignment is done only the first time the function runs (and/or might actually be done during the C init runtime phase, before main() runs, i.e. before the function ever does run).

  5. Anyway, here's the code for now.  I have not uploaded this to my Tiva yet to test.

     

    main.cpp:

    /*
     * main.c
     */
    #include <FreeRTOS.h>
    #include <task.h>
    #include <semphr.h>
    #include <queue.h>
    
    #include <stdint.h>
    #include <stdbool.h>
    #include "inc/hw_types.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_gpio.h"
    #include "inc/hw_ssi.h"
    #include "inc/tm4c123gh6pm.h"
    #include "driverlib/gpio.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/rom.h"
    #include "driverlib/rom_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/ssi.h" // for SPI
    #include "driverlib/udma.h"
    #include <string.h> // for strlen()
    #include <SPIDMA.h>
    
    #define DMA_MAX_SUPPORTED_CHANNELS 16
    SPIDMA<SSI2_BASE, 13, 12, UDMA_CH13_SSI2TX, UDMA_CH12_SSI2RX, 4, INT_SSI2, 1> SpiGk;
    volatile uint32_t DMA_Control[4 * DMA_MAX_SUPPORTED_CHANNELS] __attribute__((aligned(1024)));
    
    // C Function proto's
    extern "C" {
    void wrapper_spigk_task(void *);
    void client_test_task(void *);
    };
    
    int main(void) {
    	MAP_SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN);
    	MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI2);  // SSI2 on PB4/PB6/PB7
    	MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB); // Need this to configure PB for SSI usage
    	MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE); // Need this to configure PE for GPIO (SPI ChipSelect) usage
    	MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA); // uDMA controller
    	while (!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_SSI2)) ;
    	while (!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOB)) ;
    	while (!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOE)) ;
    	while (!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_UDMA));
    
    	// Configure PB4, PB6, PB7 as SSI pins
    	MAP_GPIOPinTypeSSI( GPIO_PORTB_BASE, (GPIO_PIN_4 | GPIO_PIN_6 | GPIO_PIN_7) );
    	MAP_GPIOPinConfigure(GPIO_PB4_SSI2CLK);
    	MAP_GPIOPinConfigure(GPIO_PB6_SSI2RX);
    	MAP_GPIOPinConfigure(GPIO_PB7_SSI2TX);
    	// Configure PE5 as GPIO Output
    	MAP_GPIOPinTypeGPIOOutput(GPIO_PORTE_BASE, GPIO_PIN_5);
    	MAP_GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_5, GPIO_PIN_5);
    
    	// Init SSI2
    	MAP_SSIClockSourceSet(SSI2_BASE, SSI_CLOCK_SYSTEM); // System CPU clock used
    	MAP_SSIConfigSetExpClk(SSI2_BASE, MAP_SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 20000000, 8); // 8MHz SPI, mode 0, 8 bits
    	MAP_SSIEnable(SSI2_BASE);  // SPI peripheral is now live.
    	MAP_uDMAEnable();
    	MAP_uDMAControlBaseSet( (void *)&DMA_Control );
    	
    	xQueueHandle spiq = SpiGk.begin();
    	xTaskCreate(wrapper_spigk_task, "SpiGK", 64, NULL, 7, NULL);
    
    	// Create a client task
    	xTaskCreate(client_test_task, "Client1", 64, spiq, 5, NULL);
    
    	// Start FreeRTOS
    	vTaskStartScheduler();
    	while(1);
    	return 0;
    }
    
    
    
    // C binding so these functions are available to FreeRTOS task creation and ISRs
    extern "C" {
    
    void placeholder_ssi2_irq_handler(void) {
    	SpiGk.handleSpiIrq();
    }
    
    void wrapper_spigk_task(void *pvParameters) {
    	SpiGk.runMainTask();
    }
    
    /*
     * pasting this here just to remember the fields...
    typedef struct {
    	xSemaphoreHandle complete;
    	const void * dataout;
    	void * datain;
    	size_t length;
    	uint8_t bitsize;
    	volatile void * cs_gpio_base;
    	uint8_t cs_gpio_pin;
    	uint32_t speed;
    } spiRequest_t;
     */
    
    char sbuf[128];
    void client_test_task(void *pvParameters) {
    	xQueueHandle spiq = (xQueueHandle)pvParameters;
    	spiRequest_t sreq;
    	sreq.complete = xSemaphoreCreateBinary();
    	sreq.bitsize = 8;
    	sreq.cs_gpio_base = 0;
    	sreq.speed = 8000000UL;
    	sreq.datain = NULL;
    	sreq.dataout = sbuf;
    	strcpy(sbuf, "This is only a test.");
    	sreq.length = strlen(sbuf);
    
    	while (1) {
    		xQueueSendToBack(spiq, &sreq, portMAX_DELAY); // Pend waiting for queue to become not-full
    		xSemaphoreTake(sreq.complete, portMAX_DELAY); // Pend waiting for SPI request to become fulfilled
    		// RTOS 20ms delay
    		vTaskDelay(20 / portTICK_PERIOD_MS);
    	}
    }
    
    }; /* extern "C" */
    
    

    SPIDMA.h, which contains the code and class definition (C++ templated classes work best when they are contained within a header file, not a .cpp file):

    /*
     * SPIDMA.h - C++ template class for a Tiva-C series SPI driver using uDMA and FreeRTOS
     *
     *  Created on: May 3, 2016
     *      Author: Eric Brundick <spirilis@linux.com>
     */
    
    #ifndef SPIDMA_H_
    #define SPIDMA_H_
    
    #include <stdint.h>
    #include <stdbool.h>
    
    
    #include <FreeRTOS.h>
    #include <semphr.h>
    #include <queue.h>
    
    // Data types used within the SPIDMA library
    typedef struct {
    	xSemaphoreHandle complete;
    	const void * dataout;
    	void * datain;
    	size_t length;
    	uint8_t bitsize;
    	uintptr_t cs_gpio_base;
    	uint8_t cs_gpio_pin;
    	uint32_t speed;
    } spiRequest_t;
    
    
    // Main code
    template <
    	uintptr_t           spi_base,
    	uint32_t            udma_tx_chan,
    	uint32_t            udma_rx_chan,
    	uint32_t            udma_tx_funcassignment,
    	uint32_t            udma_rx_funcassignment,
    	uint32_t            queue_len,
    	uint32_t            spi_interrupt_index,
    	uint8_t             spi_interrupt_prio >
    class SPIDMA {
    private:
    	volatile xQueueHandle req_queue;
    	xSemaphoreHandle irq_swi_trigger;
    	uint32_t last_speed;
    
    public:
    	__noinline
    	SPIDMA() {
    		last_speed = 0;
    	}
    
    	__noinline
    	xQueueHandle begin() {
    		irq_swi_trigger = xSemaphoreCreateBinary();
    		req_queue = xQueueCreate(queue_len, sizeof(spiRequest_t));
    
    		// Init uDMA
    		MAP_uDMAChannelAssign( udma_tx_funcassignment );
    		MAP_uDMAChannelAssign( udma_rx_funcassignment );
    		MAP_uDMAChannelAttributeEnable( udma_tx_chan, 0 ); //
    		MAP_uDMAChannelAttributeEnable( udma_rx_chan, 0 ); //
    
    		// Tell SSI to allow DMA
    		MAP_SSIDMAEnable(spi_base, SSI_DMA_TX | SSI_DMA_RX);
    		MAP_IntEnable(spi_interrupt_index);
    		MAP_IntPrioritySet( spi_interrupt_index, spi_interrupt_prio );
    
    		return req_queue;
    	}
    
    	__noinline
    	void handleSpiIrq() {
    		// This should fire when an SPI transfer is complete.
    		BaseType_t xHigherPriorityTaskWoken = false;
    
    		uint32_t udma_ch_mask = (1 << udma_tx_chan) | (1 << udma_rx_chan);
    		if (MAP_uDMAIntStatus() & udma_ch_mask) {
    			MAP_uDMAIntClear(udma_ch_mask);
    			// Signal software handler that we're done with transfer
    			xSemaphoreGiveFromISR(irq_swi_trigger, &xHigherPriorityTaskWoken);
    		}
    
    		portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
    	}
    
    	__noinline
    	void runMainTask() {
    		spiRequest_t currentReq;
    		portBASE_TYPE qRT; // xQueueReceive return value
    
    		// SSI Tx/Rx FIFO
    		volatile uintptr_t * ssi_FIFO = (volatile uintptr_t *)(spi_base + SSI_O_DR);
    
    		while (1) {
    			qRT = xQueueReceive(req_queue, &currentReq, portMAX_DELAY);  // Wait for incoming request
    			// Service request:
    			if (pdPASS == qRT) {
    				// Ascertain which mode - TX, RX, or both
    				if (currentReq.length < 1 || currentReq.dataout == NULL) {
    					xSemaphoreGive(currentReq.complete); // nothing to do
    					continue;
    				}
    
    				uint32_t ctrltxsize = UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_8;
    				uint32_t ctrlrxsize = UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_8;
    				if (currentReq.bitsize > 8) {
    					ctrltxsize = UDMA_SIZE_16 | UDMA_SRC_INC_16 | UDMA_DST_INC_NONE | UDMA_ARB_8;
    					ctrlrxsize = UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_8;
    				}
    
    				// Prepare TX
    				MAP_uDMAChannelControlSet( (udma_tx_chan | UDMA_PRI_SELECT), ctrltxsize );
    				MAP_uDMAChannelTransferSet(udma_tx_chan, UDMA_MODE_BASIC, (void *)currentReq.dataout, (void *)ssi_FIFO, currentReq.length);
    
    				if (currentReq.datain != NULL) {
    					// Also prepare RX
    					// This is the only way to do RX (in fact that makes sense, as SPI master requires
    					// the master initiate transfers, which necessarily requires TX)
    					MAP_uDMAChannelControlSet( (udma_rx_chan | UDMA_PRI_SELECT), ctrlrxsize );
    					MAP_uDMAChannelTransferSet(udma_rx_chan, UDMA_MODE_BASIC, (void *)ssi_FIFO, (void *)currentReq.datain, currentReq.length);
    					MAP_uDMAChannelEnable(udma_rx_chan);  // Prime RX side
    				}
    
    				// Configure SPI peripheral speed
    				if (currentReq.speed > 0 || last_speed == 0) {
    					MAP_SSIConfigSetExpClk(spi_base, MAP_SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, currentReq.speed, currentReq.bitsize);
    					last_speed = currentReq.speed;
    				}
    
    				// Activate GPIO CS
    				bool do_gpiocs = false;
    				if (currentReq.cs_gpio_base != 0 && currentReq.cs_gpio_pin) {
    					do_gpiocs = true;
    					MAP_GPIOPinWrite(currentReq.cs_gpio_base, currentReq.cs_gpio_pin, 0);
    				}
    				MAP_uDMAChannelEnable(udma_tx_chan);  // BOOM! Off to the races.
    				// Pend on binary semaphore for SSITx IRQ to signal uDMA completion
    				xSemaphoreTake(irq_swi_trigger, portMAX_DELAY);
    				// Deactivate GPIO CS
    				if (do_gpiocs) {
    					MAP_GPIOPinWrite(currentReq.cs_gpio_base, currentReq.cs_gpio_pin, currentReq.cs_gpio_pin);
    				}
    				// Done; signal binary semaphore currentReq.complete
    				xSemaphoreGive(currentReq.complete);
    			} /* if (pdPASS == qRT) */
    		} /* while(1) */
    	} /* runMainTask method */
    
    	// Client-side access will be implemented by a sister class defined below.
    };
    
    
    // Arduino compatibility client class
    class SPIClass {
    private:
    	xQueueHandle req_queue;
    	spiRequest_t reqcache;
    	uint32_t defaultSpeed;
    public:
    	__noinline
    	SPIClass() {
    		defaultSpeed = 4000000;  // Arduino default
    	}
    
    	// commandeered the setModule method for defining the SPI gatekeeper queue
    	__noinline
    	void setModule(xQueueHandle q) {
    		req_queue = q;
    	}
    
    	__noinline
    	void setDataMode(uint8_t dm) {
    		// does nothing here
    	}
    
    	__noinline
    	void setClockDivider(uint32_t clockDiv) {
    		// Do something intelligent with the clock rate
    	}
    
    	__noinline
    	void setSpeed(uint32_t s) {
    		defaultSpeed = s;
    		reqcache.speed = s;
    	}
    
    	__noinline
    	void setBitOrder(uint8_t  { } // does nothing here
    
    	__noinline
    	void begin() {
    		reqcache.bitsize = 8;
    		reqcache.cs_gpio_base = 0;
    		reqcache.cs_gpio_pin = 0;
    		reqcache.length = 1;
    		reqcache.speed = defaultSpeed;
    		reqcache.complete = xSemaphoreCreateBinary();
    	}
    
    	__noinline
    	void end() {} // does nothing
    
    	__noinline
    	uint8_t transfer(uint8_t inb) {
    		uint8_t inbuf, outbuf;
    
    		inbuf = inb;
    		reqcache.bitsize = 8;
    		reqcache.datain = &outbuf;
    		reqcache.dataout = &inbuf;
    		reqcache.length = 1;
    
    		// Submit SPI request to queue, blocking if full
    		xQueueSendToBack(req_queue, &reqcache, portMAX_DELAY);
    		// Wait until SPI request is fully complete
    		xSemaphoreTake(reqcache.complete, portMAX_DELAY);
    
    		// Return outbuf (return data)
    		return outbuf;
    	}
    
    	__noinline
    	uint16_t transfer16(uint16_t inw) {
    		uint16_t inbuf, outbuf;
    
    		inbuf = inw;
    		reqcache.bitsize = 16;
    		reqcache.datain = &outbuf;
    		reqcache.dataout = &inbuf;
    		reqcache.length = 1;
    
    		// Submit SPI request to queue, blocking if full
    		xQueueSendToBack(req_queue, &reqcache, portMAX_DELAY);
    		// Wait until SPI request is fully complete
    		xSemaphoreTake(reqcache.complete, portMAX_DELAY);
    
    		// Return outbuf (return data)
    		return outbuf;
    	}
    
    	__noinline
    	uint16_t transfer9(uint16_t inw) {
    		uint16_t inbuf, outbuf;
    
    		inbuf = inw;
    		reqcache.bitsize = 9;
    		reqcache.datain = &outbuf;
    		reqcache.dataout = &inbuf;
    		reqcache.length = 1;
    
    		// Submit SPI request to queue, blocking if full
    		xQueueSendToBack(req_queue, &reqcache, portMAX_DELAY);
    		// Wait until SPI request is fully complete
    		xSemaphoreTake(reqcache.complete, portMAX_DELAY);
    
    		// Return outbuf (return data)
    		return outbuf;
    	}
    };
    
    
    
    #endif /* SPIDMA_H_ */
    
    

    tm4c123gh6pm_startup_ccs_gcc.c sections related to the IRQ:

    //*****************************************************************************
    //
    // External declarations for the interrupt handlers used by the application.
    //
    //*****************************************************************************
    // To be added by user
    extern void placeholder_ssi2_irq_handler(void);
    
    extern void xPortPendSVHandler(void);
    extern void xPortSysTickHandler(void);
    extern void vPortSVCHandler(void);
    
    //*****************************************************************************
    //
    // The vector table.  Note that the proper constructs must be placed on this to
    // ensure that it ends up at physical address 0x0000.0000 or at the start of
    // the program if located at a start address other than 0.
    //
    //*****************************************************************************
    __attribute__ ((section(".intvecs")))
    void (* const g_pfnVectors[])(void) =
    {
        (void (*)(void))((uint32_t)pui32Stack + sizeof(pui32Stack)),
                                                // The initial stack pointer
        ResetISR,                               // The reset handler
        NmiSR,                                  // The NMI handler
        FaultISR,                               // The hard fault handler
        IntDefaultHandler,                      // The MPU fault handler
        IntDefaultHandler,                      // The bus fault handler
        IntDefaultHandler,                      // The usage fault handler
        0,                                      // Reserved
        0,                                      // Reserved
        0,                                      // Reserved
        0,                                      // Reserved
        vPortSVCHandler,                      // SVCall handler
        IntDefaultHandler,                      // Debug monitor handler
        0,                                      // Reserved
        xPortPendSVHandler,                      // The PendSV handler
        xPortSysTickHandler,                      // The SysTick handler
        IntDefaultHandler,                      // GPIO Port A
        IntDefaultHandler,                      // GPIO Port B
        IntDefaultHandler,                      // GPIO Port C
        IntDefaultHandler,                      // GPIO Port D
        IntDefaultHandler,                      // GPIO Port E
        IntDefaultHandler,                      // UART0 Rx and Tx
        IntDefaultHandler,                      // UART1 Rx and Tx
        IntDefaultHandler,                      // SSI0 Rx and Tx
        IntDefaultHandler,                      // I2C0 Master and Slave
        IntDefaultHandler,                      // PWM Fault
        IntDefaultHandler,                      // PWM Generator 0
        IntDefaultHandler,                      // PWM Generator 1
        IntDefaultHandler,                      // PWM Generator 2
        IntDefaultHandler,                      // Quadrature Encoder 0
        IntDefaultHandler,                      // ADC Sequence 0
        IntDefaultHandler,                      // ADC Sequence 1
        IntDefaultHandler,                      // ADC Sequence 2
        IntDefaultHandler,                      // ADC Sequence 3
        IntDefaultHandler,                      // Watchdog timer
        IntDefaultHandler,                      // Timer 0 subtimer A
        IntDefaultHandler,                      // Timer 0 subtimer B
        IntDefaultHandler,                      // Timer 1 subtimer A
        IntDefaultHandler,                      // Timer 1 subtimer B
        IntDefaultHandler,                      // Timer 2 subtimer A
        IntDefaultHandler,                      // Timer 2 subtimer B
        IntDefaultHandler,                      // Analog Comparator 0
        IntDefaultHandler,                      // Analog Comparator 1
        IntDefaultHandler,                      // Analog Comparator 2
        IntDefaultHandler,                      // System Control (PLL, OSC, BO)
        IntDefaultHandler,                      // FLASH Control
        IntDefaultHandler,                      // GPIO Port F
        IntDefaultHandler,                      // GPIO Port G
        IntDefaultHandler,                      // GPIO Port H
        IntDefaultHandler,                      // UART2 Rx and Tx
        IntDefaultHandler,                      // SSI1 Rx and Tx
        IntDefaultHandler,                      // Timer 3 subtimer A
        IntDefaultHandler,                      // Timer 3 subtimer B
        IntDefaultHandler,                      // I2C1 Master and Slave
        IntDefaultHandler,                      // Quadrature Encoder 1
        IntDefaultHandler,                      // CAN0
        IntDefaultHandler,                      // CAN1
        0,                                      // Reserved
        0,                                      // Reserved
        IntDefaultHandler,                      // Hibernate
        IntDefaultHandler,                      // USB0
        IntDefaultHandler,                      // PWM Generator 3
        IntDefaultHandler,                      // uDMA Software Transfer
        IntDefaultHandler,                      // uDMA Error
        IntDefaultHandler,                      // ADC1 Sequence 0
        IntDefaultHandler,                      // ADC1 Sequence 1
        IntDefaultHandler,                      // ADC1 Sequence 2
        IntDefaultHandler,                      // ADC1 Sequence 3
        0,                                      // Reserved
        0,                                      // Reserved
        IntDefaultHandler,                      // GPIO Port J
        IntDefaultHandler,                      // GPIO Port K
        IntDefaultHandler,                      // GPIO Port L
        placeholder_ssi2_irq_handler,                      // SSI2 Rx and Tx  **** Modified by User ****
    
  6. Okay, coming about to my first FreeRTOS class imagined as a C++ class.

     

    Couple things:

     

    1. main.c has to be main.cpp, otherwise stuff just doesn't build right.

    2. C functions inside main.c should be declared with extern "C", which I will illustrate soon.  The reason for this is that without it, the compiler will mangle the symbol name a bit so other code modules might not recognize the function name if it's declared via extern.

    3. portYIELD_FROM_ISR() should take the xHigherPriorityTaskWoken variable directly, NOT a pointer to it as I did in previous examples!  Oops.  I didn't see this until I started getting "ISO C++ forbids comparison between pointer and variable" type of compiler errors related to that call.

    4. Peripheral base addresses are defined in hw_memmap.h as uint32_t's, not pointers.  The TivaWare driverlib calls expect it that way too.  This is critically important when parameterizing it for C++ templates.  If you need to use a pointer to the address inside the C++ class, you just have to compose it with e.g. volatile uint32_t *ssi_FIFO = (volatile uint32_t *)(ssi_base + SSI_O_DR); or something.

    5. In Project Properties > Compiler > Misc, remove the "-std=c99" option, as this applies to C only and will bomb the compile on C++.

     

    Also, my understanding is that FreeRTOS won't run a C++ method directly as a task and likewise the ARM NVIC interrupt vector table can't have a C++ method registered as an ISR, you need to wrap it in a C function.  C functions inside a .cpp file do understand the concept of objects and will generate compiler code that correctly loads (internally, into the register parameters to the C++ method call) the pointer to the correct object before running.

     

    So my model here is to create wrapper C functions that call the instantiated C++ object's methods for ISRs and for the FreeRTOS task function, then the actual "code" is contained within the C++ class and references all the private variables compartmentalized within that class.

  7. The char set to 0 is restored to the original buffer rather than the new buffer. So the new buffer does not get the right most character. Kind of feels like a bug?

    I think it depends on whether right is meant to be inclusive or not.  I suspect it's not meant to be inclusive, hence why it works this way.  So the substring comprises left to (right-1).  That's pretty common in other programming languages IIRC.

  8. Line 12 does set the right character to 0, but then after the substring is copied into "out", it's restored (see line 14).

     

    I'm actually not sure about the memory management aspects here, particularly of line 8.  I would suspect this allocates from the stack which would corrupt after exit, but that might not be the case.  Have you experienced any issues with this library?

  9. Find the MSP430.dll or libmsp430.so from CCS and copy it to Energia's hardware/tools/msp430/bin or hardware/tools/msp430/mspdebug directory (look to see which one you have).  That'll synchronize the MSP Debug Stack library between the two.

     

    CCS's MSP430.dll on Windows is located in:

     

    C:\ti\ccsv6\ccs_base\DebugServer\drivers

  10. F5529 doesn't support EnergyTrace so I can't optimize the performance of the sensor node. That is one of the reason why I want to migrate to FR6989. Second reason is that in general compact design is more reliable i.e. LCD is  part of LP board and I guess it may consume less power.

    what @@abecedarian said... The power consumption of the LCD entirely depends on how fancy an LCD you use.

     

    The other consideration is that, since you only need the LCD for occasional "configuration" purposes, the board housing that LCD can provide power for itself and/or power (or recharge) the WSN board.  Using level shifters in the bus interface the former option, i.e. the LCD board power itself, is easily doable.

  11. Thanks for the tip! Just changed the compiler to G2553 and it compiled all the way through without any complaints. So I guess I'll have to buy that new microprocessor. Do you know if it will work for the launchpad I am currently using with the G2452?

    Most likely, can you share what "revision" of the MSP-EXP430G2 launchpad you have?  It should work either way but the newer v1.5 launchpads support the hardware UART on the G2553 (only 9600bps) better.

  12. On @@abecedarian 's note about LCDs, one interesting option would be to have the LCD interface a pluggable module that you attach only when you need it... and have the board designed to accept such "hot plugged" hardware.  I'm not 100% certain how the hot plug interface should work but I do know there are special "bus transceiver" ICs that can make this seamless/less prone to screw with the board's operation.

  13. A FRAM backed MSP432... or even TM4C would be sweet!

     

     

    I've never had an issue with an F5529LP "forgetting" its program. I have had issues where connecting it to the computer and flipping back and forth between CCS and Energia has required the FET section firmware be "updated" though, and have had this occur with other LP's too.

     

    FRAM is not going to consume any more power than FLASH; I suspect it'll consume less since it doesn't require the higher voltages FLASH needs to erase.

     

    All the FR parts, IIRC, have 2KB SRAM which can be set to be inactive in LPM3/4 so not consume any power in those modes, but wakeups might take a little longer.

     

    Energia supports the 6989, but I'm not sure how that goes considering the extended addressing required by the chip. Compiling a simple sketch shows 130,048 byte maximum on Energia 17 so maybe it's not an issue?

     

     

     

    Anyhow, an LCD is sort of a non-issue for me. LCD character displays can be had on eBay for fairly cheap so could be an expansion of sorts if that's acceptable. e-paper displays are an option as well. I actually like the idea of the display being external to the LP since it opens up enclosure options due to not being on the LP itself, in a fixed location.

    The "byte maximum" in Energia is BS and driven by the values inside boards.txt IIRC.  I haven't looked at Energia's FR6989 support internals yet though.

  14. F5529 sometimes doesn't run the software when it's connected to CC1120 unless I upload the software again. While FR5969 works properly.

     

    Some LPs are made in China and others in USA. I can show you the proof if you still hesitated about that.

     

    I bought FR5969 before six months and have no idea about the new price.

    I'll take your word for it ;)

     

    I like the FR5969 better overall anyway.  F5529 has plenty of cool stuff to talk about but FRAM is neat.  I have a lightning sensor project that uses the FRAM as its data storage device (and that whole concept should work well for WSN nodes when reliable communication links aren't guaranteed but the data should be reported).

     

    The thing I hate about the FR6989 is that since its 128KB FRAM lives mostly in the upper address space (requiring 20-bit addressing mode), the old msp430-gcc that ships with Energia doesn't support it, whereas the new msp430-elf-gcc that ships with CCS has had lots of issues to work out (though I haven't tried the very latest version, maybe it's stable now).  Great that it's there, just sucks that the software support requires finagling with linker scripts 'n stuff.  Give me a FRAM MSP432 already.

  15. First of all, If you have a box of F5529LP you can see made in China.

     

    When I use both kits for the same application. After I unplug the kit from USB and connect it back to the port, FR5969 start the operation normally while F5529 needs downloading the software again. Why? That happens many times.

     

    Can you give a reason why there is a margin in prices of FR5969 ($24) and FR6989 ($18)?

     FR6989 has Built in LCD and has higer FRAM (128KB instead of 64KB in FR5969).

    Yeah the LP's are probably all made in China, just the chips are made in TX (and packaged in Mexico if I'm not mistaken).

     

    For software, do you mean the F5529LP needs a new firmware update on its FET?  Or do you mean the chip itself is missing the code you uploaded?  The latter would be very odd (and probably just a bad chip on your board).  I've never seen that happen with any of mine.

     

    As for TI's prices .... I see $16 for the FR5969 and $18 for the FR6989, and what I will say is TI's pricing for their launchpads makes no sense to me, probably it's priced for promotional or educational use which is why the prices often seem questionable when considering the amount of components onboard.  All of those components are likely dirt cheap for TI anyhow.

  16. FR4133 has 16 KB FRAM which makes it unsuitable for my application. However FR6989 has good features but the size of RAM is large which means more power to dissipate. Do you agree with me?

     

    Based on my experience, FR5969 provides better performance stability over F5529. I think that is because FR5969 is USA made while F5529 is China made. Do anyone has an idea about FR6989?

    I don't know where your last line came from, but I doubt there's any difference in where the chips are made... (IIRC all MSP430's are made in the USA, in Dallas near TI's headquarters)

     

    What do you mean by "performance stability"?

×
×
  • Create New...