Jump to content
43oh

tripwire

Members
  • Content Count

    193
  • Joined

  • Last visited

  • Days Won

    14

Posts posted by tripwire

  1. Looking at the chip's errata sheet though, check out USCI40:

    http://www.ti.com/lit/er/slaz440g/slaz440g.pdf page 9

     

    That bug only happens with UCCKPH=1, which isn't the case in the slave code shown. I suspect the problem might just be a mismatch between the Raspberry Pi's SPI mode and the one selected on the g2553. That can manifest as a one-bit offset in one direction or the other.

     

    You can use ioctl(fd, SPI_IOC_WR_MODE, &mode) to set the mode on the raspi end. Doing that means you can avoid setting UCCKPH=1 on the g2553 and not have to worry about the USCI40 problem. The bad news is that the arduino slave code will need changing to match.

     

    I think that setting SPI_MODE_3 on the raspi will match what you've selected on the g2553, and will let you remove the bit shift workaround.

  2. Ah, yes, that looks like a quirk of the SSI. The default SSI mode apparently adds a delay of 1.5 cycles between bytes to pulse the SSInFss line off.

     

    post-30355-0-59669900-1460410326_thumb.png

     

    I think that calling MAP_SSIAdvFrameHoldEnable(SSI2_BASE) during SSI setup might remove that delay.

  3. I used sprintf on CC2650 and it smashed the stack :(
     
    When I was looking at my code in the debugger the SP was about 2/3 of the way down into the stack, and beyond that the memory all appeared unused. Eventually I spotted a few bytes had been written right at the limit of the stack. Apparently sprintf needs a 510 byte buffer to format the string version of numbers from %d etc. I only wanted to convert a 32 bit value to a hexadecimal string!
     
    I think I was spoiled by MSP430 which defaults to "minimal" (s)printf using a tiny internal formatting buffer. It only breaks the C standard, not the stack limit!
     

    Keep getting error message in CCS saying unable to program the LP (not exactly but something very similar to that meaning). 100% sure the board is connected. Unplugged the USB and plugged in again, restarted CCS and restarted PC. Turns out I tried to program a non-existent 2553 as I moved it out from the LP to a breadboard :rolleyes:


    Me too! Sometimes I use the MSP432 or FR5969 launchpads to energytrace another launchpad. When the time comes to reprogram the target I always forget to remove the external VCC/GND jumper wires and reconnect the target to its emulator.

  4. Can you queue up several spi dma transactions?

     

    At the moment the code is using basic DMA transfer mode, which means the CPU has to wake up to prepare the next DMA transfer.

     

    The ARM uDMA also offers ping-pong mode, where it automatically kicks off a second transfer once the first is completed. Meanwhile the CPU wakes up to set the inactive DMA control structure up for the next transfer. This double buffering means the DMA is kept active and doesn't have to wait on the CPU.

     

    Finally there's scatter/gather mode, where the DMA module writes its own control structure(s), allowing up to 256 pre-planned transfers. That one's the most fun ;)

     

    How fast can the spi bus go flat out?

     

    I'm curious about that too. I'm wondering why SPI_CLK has pauses between bytes in the latest zoomed in scope trace. What with the TX FIFO and DMA feeding the SSI I'd have hoped the Tiva would manage continuous output at 8MHz.

  5. If anyone has achieved 0.4uA  please could you share the code as i can only get in down to 220uA.

     

    I might be able to take a crack at this.  Post your whole sketch and I'll play around a bit.

     

    I am using energia but have CCS setup as well.

     

    I don't use Energia myself, but I had some trouble getting the datasheet power consumption on FR5969 launchpad.

     

    There were two issues that caused excess power consumption in my case:

    1. I'd set the unused pins to output low, but the UART TX/RX jumpers were in place on the launchpad. The UART output on the ez-FET sits at VCC when nothing is being sent, so grounding that pin draws a lot of current. Removing the UART jumpers fixed that.
    2. I hadn't initialised the LFXT properly. As far as I can remember that results in the DCO being enabled to source ACLK, even in LPM3.

    Once I fixed those I was able to achieve the datasheet specifications. I'm not sure how applicable those points are to Energia, though.

  6. Now that's no good!  Even if the point was to spam the SPI bus with data, doing so in coherent blocks/sentences would be preferable.  Those sentences could be coherent blocks of data or control information for an Ethernet peripheral, SPI-attached radio (CC3100, nRF24L01+, etc) or who knows.  Having the data cut in the middle of a logically-contiguous block could cause corruption (especially if separate SPI Chip Select lines are used - but - the task never had a chance to complete its SPI I/O and then deselect the intended peripheral's SPI CS line before the next task goes to town).  Moreover, electrical problems/short circuits could result if multiple SPI slave devices try driving the MISO line due to more than 1 having their Chip Select line selected.  How do we manage this in an RTOS environment?

     

    This is where it gets really interesting! Any RTOS can turn out a clean-looking led blinking program. The true test is how it deals with shared resources. I'm looking forward to the next few posts! :)

  7. I will take a look once I find some time, but this could be caused by different default settings of the display driver (I am setting only few basic things in configuration function.)

    Should be an easy fix.

     

    Yeah, it looks like RGB vs BGR colour ordering. I guess the displays that do this need some specific setup to pick the right mode. If they don't offer a setting for component order then the red and blue bits would need to be swapped in setColor.

  8. The lite version has most of the features and is code un-limited.

    The Pro version is $59 a month.

     

    I'm using CCS for most of my as well as ARM-gcc with eclipse.

    What do you think of Atollic's monthly fee? For me I'd rather pay upfront... but limited to under $500. The subscription fee does have it's pros though... lifetime support and updates+pro tools.

     

    Well, it's possible to get a perpetual licence for $2795 (yikes!). That's equivalent in cost to almost four years of subscription. The subscription model gives you updates as long as you keep paying whereas the perpetual licence only gives that for a year. On the other hand, the perpetual licence is perpetual :)

  9. These scores suggest a real >2x performance breakthrough in low power consumption from Ambiq Micro's Apollo device:

     

    http://www.eembc.org/ulpbench/index.php

     

    I wonder if this technology is really ready for prime time and how the current industry leaders (TI, STM etc...) will respond/react... What do you think?

     

    From the test notes it looks like the improvement in benchmark score is as much down to active mode current as sleep mode.

     

    On the sleep mode side of things I think Ambiq are fortunate to have a sleep mode that includes exactly the features required for the EEMBC test. I think they're using the Deep Sleep + RTC mode, which is claimed at 198nA. Compare that with the MSP432 which uses LPM3 for the test at 850nA. MSP432 does have LPM4 at 25nA, but that has no RTC so can't be used in this case. The preliminary Apollo datasheet linked from EEMBC says the device has a shutdown mode which sounds very similar to LPM4, but unfortunately no specs are given.

     

    The 34?A/MHz active power consumption claimed in the datasheet is impressive. Maybe that's down to the "Subthreshold Power Optimized Technology" mentioned in the datasheet. If that's the case I'd guess it would be difficult to match with current technologies. The big players might have new processes up their sleeve that will let them catch up, or maybe they'll just buy Ambiq out to get their IP. Ambiq was only founded in 2010, so probably still has VCs looking for a profitable exit...

  10. About 10000 cycles write-erase per segment... well 10000*5/(60*24)= 34 days of time of life.... ouch.... (ok, i can store the end of array, say every hour and/or when it is externally ordered, but I don't see that very elegant...)

     

    That estimate is based on erasing the segment every time you write a single value (because you're updating "end of array" stored in flash). If you use findEndOfDataPoisition on startup you don't need the end of array stored in flash any more. You can then write your log data as 16-bit words, only erasing when starting a new segment of log data.

     

    If you're writing to the information memory segments on MSP430G2553, you'd be writing 32 temperature measurements per erase. In that case the memory would last for at least 1088 days. If you allocated some of main memory instead you'd get 256 measurements stored per erase, which would be over 23 years endurance.

  11. So my question is:
    Can the crystal from the sparkfun website can be used instead ?
    Do I need to solder the "barrel"/body ?

     

    It looks like the sparkfun crystal is slightly bigger than the stock launchpad one. It's also a through-hole part rather than SMT. I think it would be possible to push the leads through the plated through-holes on either side of the pads used by the stock SMT crystal. Then you could solder the two wires from the back of the board, which might be easier than surface mounting.

     

    The body connection can probably be made with the sparkfun crystal even though it doesn't have a flat underside. Having said that, the body connection is not essential. It grounds the case, which helps to shield against any interference. It should still work just fine without it, and it's better to leave it unconnected than to overheat the crystal if you're finding it awkward to solder.

  12.  

    Both write modes use a sequence of individual write instructions, but using the block write mode is approximately twice as fast as byte or word mode, because the voltage generator remains on for the complete block write. Any instruction that modifies a destination can be used to modify a flash location in either byte or word write mode or block write mode. A flash word (low and high bytes) must not be written more than twice between erasures. Otherwise, damage can occur.

     

    WTF? If, for example, I write 3 times lastPositionUsedInDataSegments (firt bytes in a flash segment) without call "erase segment" fuction I can damage my flash memory?????

     

     

    As I understand it, the "damage" referred to here is to the data contained in the same segment, not physical damage to the flash memory hardware. Repeated overwrites without erase can disturb the contents of nearby flash cells. The same can happen if the maximum cumulative programming time is exceeded.

     

    Flash memory does get damaged physically by writing (particularly the erase process). The MSP430G2553 datasheet guarantees at least 10000 erase cycles per segment without damage.

  13. Exactly. I don't remember the part number of the flash I had used at the time, but it was a sector based flash where you would fill a RAM buffer with data and then when it was full, you would flash the entire sector all at once. Since the erased state of the flash was 0xFF in all locations, you could do byte writes by filling the buffer with all 0xFF bytes, and then adding new bytes to it and flashing the entire sector each time an 0xFF was changed to a new data value. It definitely would work that way when I tested it, but the datasheet warned that this kind of write was not recommended and could flip neighboring bits unintentionally.

     

    Thanks, I understand the issue now.

     

    The flash I'm using has a page-sized RAM buffer too, but it's able to address individual bytes. You can load up to 256 bytes into the buffer and then trigger the write by releasing chip select. At that point the buffered values get written to flash starting at the specified address. There's a restriction that only bytes in the same page as the start address can be written, so the write wraps around if it hits the end of the page. It says that it's possible to program part of a page as long as the current write doesn't overlap the already programmed areas.

     

    Beyond that the datasheet is pretty vague. It doesn't have any warnings about cumulative programming time like the flash in the MSP430 MCUs. There's no mention of write-disturb or bit flipping. I even had to go to the winbond website to confirm that the chip was NOR flash rather than NAND... that's not in the datasheet either.

  14. I recommend you avoid having a file index stored in one area of the flash because you're going to wear that memory out by constantly writing and rewriting to it.

     

    I understand how that would be a problem for a typical file system where you'd need to read/erase/modify/write the index whenever a file was modified.

     

    In my case the index is an append-only structure, the same as the logged data. A log that grows from the start until it fills the whole memory would erase and write every data page once. Meanwhile the active metadata block would be erased once, then each byte of the alloaction table would be written once in turn. When the log wraps around to the start the other metadata block is used in the same way. That means the metadata blocks are actually erased and written half as often as the pages that hold the data.

     

    [...] and you also have to worry about some flash devices being sensitive to bits flipping if you repeatedly write the same bits to the same sector without an erase.

     

    Do you mean overprogramming a flash byte with its current value (ie programming it but not changing the value)?

  15. So to understand whats happening: When I call pMySubClass=new SubClass(), a new instance of SubClass is created and the address of its memory is stored in pMySubClass. But different to just calling SubClass mySubClass; and getting the memory address via pMySubClass= &mySubClass, the instance created witch new SubClass() exists until I call delete while mySubClass is deleted at the end of the function?

     

    Yes, that's basically what's happening.

     

    As dynamic memory allocation does not work in the embedded environment without OS, creating and deleting instances multiple times in this way would normally cause troubles, but that is no problem here, since my instance is used and never deleted until power down?

     

    To be clear, dynamic allocation doesn't require an OS. The "new" and "malloc" functionality is provided by the Runtime Support Library, which also contains the initialisation code that runs before main(). That library is included with the C/C++ compiler and gets built in to your project automatically. On embedded platforms sometimes the heap size is set to zero by default, however, and that needs to be increased to allow dynamic allocation. I guess that's already done if you're using energia.

     

    The problem is more to do with what happens to the heap structure used to manage the dynamic allocations.

     

    If your program is continually allocating and freeing memory while it runs you run the risk of forgetting to free some memory. When that happens you end up with less free memory available until the next reset. It's possible for all the free space in the heap to leak away, and eventually no allocations are possible.

     

    Also, allocating and freeing memory during runtime can cause the free space on the heap to become fragmented to the extent that a big allocation fails. If you allocate a couple of different memory blocks like so:

    A *a = new A(); // size = 4
    B *b = new B(); // size = 2
    

    Then a heap of size 8 might look like this ("|" marks the start and end of the heap):

     

    |aaaabb__|

     

    Now try this:

    delete a;
    C *c = new C(); // size = 6
    

    The heap would end up like this after the delete:

     

    |____bb__|

     

    Now there's six spaces free, but they're not in a contiguous block so new C() will fail. Different patterns of allocation and deletion can produce different results. In this case the program would work if b got allocated before a. Unconstrained patterns of allocation and deletion make it hard to work out whether a particular allocation will succeed. You need to inspect the internal state of the heap or know the full history of allocation/release to find out whether the free space is all in one block or not.

     

    Finally, the allocator might take longer to return when the memory gets fragmented. That's no good for real-time applications.

     

    For these reasons it's common to avoid allocating and deleting memory during runtime in embedded software. That can be done by never using new/malloc, but other options are available.

     

    As spirilis pointed out, it's fine to allocate memory dynamically at startup if you know it's needed for the whole lifetime of the program. If there's no deallocation the heap can't get fragmented and there's no risk of memory leaks if all the allocation is done at startup.

     

    The other pattern that avoids fragmentation is where later allocations are always deleted before earlier ones. That's similar to the way local variables get stored on the stack. A stack keeps all the used memory at one end and the free memory at the other, so it can't get fragmented. You just have to be sure there's enough stack space for the maximum possible amount used.

  16. Another way is to use the first byte of each page as an indicator whether a page is already in use. Simply set it to 0 (or any other value than 0xFF) when writing the page. The application then simply has to search for a page that starts with 0xFF to find an empty page.

     

    That's a good point; effectively that method would distribute the bytes from the allocation table throughout the whole memory. It would avoid the need to keep two copies of the metadata and neatly sidesteps any edge cases where it could get out of sync with the data. Much simpler!

     

    You'd have to be careful to always erase the next block before writing the last page of a block, however. If that's not done the boundary between old and new data would be lost.

     

    Also it means that the initialisation code needs to search through the pages looking at the initial bytes to find the start of free space. That's no problem if the data needs to be read anyway, but my firmware just needs to find the end to continue writing. Having the metadata in contiguous blocks means it can be loaded in bulk, which is a bit more convenient.

     

    Something I noticed while writing the code is that the first 32 bytes of the allocation tables are free because they map back onto the metadata blocks. I've used eight of those bytes to hold a second-level allocation table. After checking which metadata block is newest the code reads the eight byte table to find the active metadata page. That whole page is read and searched to find the next free page. The result is that the initialisation takes three 8-byte reads and a full page read rather than up to 2048 individual byte reads.

     

    With this particular flash chip it would be possible to do something similar for the distributed metadata approach. Rather than reading the first byte of every page you could just check the last page of each erase unit: those where (pageIndex % 16) == 15. If that page is free then check the other pages in the block, otherwise keep going. This works because the blocks are erased completely and fill from their start to their end in order. The final page of the block is always free until all the other pages are in use. That would give a worst-case of 143 byte reads to find the next page.

  17. I've just got a new storage management system working on the SensorTag, so it's time for another update...

     

    As mentioned previously, the altitude measurements are buffered in RAM until there's enough to fill a 256-byte page of the flash memory. The buffered page gets written to the flash and the current page index (stored in RAM) is incremented. That means the altitude log fills successive addresses in the flash memory, starting from zero. That's fine for the first run, but power-cycling would reset the page index and make the program start logging from zero again. To work around this I've been updating a hardcoded log start address in the firmware to start on the next free page. That required reflashing the firmware before every trip. Obviously it would be a lot nicer if the firmware could figure out where to write next without any intervention.

     

    Ideally I wanted the firmware to treat the flash as a circular buffer, overwriting old values with new ones when the flash was full. That could be done by storing a couple of page indices alongside the data, updating them as pages are written. It would essentially be a very basic filesystem. Unfortunately it's not as straightforward as I just made it sound. The problem is down to the way flash memory works.

     

    Flash memory is a bit peculiar in that the "write" operation is only capable of changing bits from 1 to 0. To change bits from 0 back to 1 requires a separate "erase" operation. That wouldn't be so bad, but it turns out that the "erase" operation can't be performed on individual bytes. Instead the erase operation must be used on a block of multiple bytes (sometimes called an "erase unit"). In the case of the SPI flash on the SensorTag, the smallest erase unit size is 4KB (or 16 pages). Modifying the value of a single byte requires reading the containing 4KB block into RAM, erasing it from flash and then writing back the modified data.

     

    The CC2650 has enough memory to cope with this, but it has its downsides. A block erase can take up to 300ms which is an eternity in microcontroller terms. It also takes a lot of power; that's bad in itself but the extra current draw might cause a tired cell's voltage to drop into brownout. Power loss during the erase or write-back could result in corrupted data.That would be bad news if it affected the filesystem metadata.

     

    There's various ways around this, but I've settled on a system that avoids the need to modify previously written metadata values. I'm reserving two 4KB blocks for metadata, one of which is active and gets updated when a data page is stored. Approximately 2KB is used to store an allocation table (one byte of metadata for each page of data). When a page of data is written the corresponding byte of the allocation table is set. If the allocation table value is 0xFF then the page is free, otherwise it is in use. I'm using the byte to hold an index identifying the trace that the data page belongs to. Each byte in the table gets written to once as the log expands to fill the whole flash memory.

     

    Once all the data pages have been used the logger returns to the beginning of the circular buffer. The oldest block is erased to free some space, which happens every time the free space is used up. Page writes are now recorded in the second metadata block. The metadata blocks each have a sequence number and any values in the newest one override the corresponding values from the older one. Once the second metadata block is full the first is no longer needed, so it can be erased and reused.

     

    This arrangement leaves 504KB for data, and the data blocks get erased once only for each 504KB logged. The metadata blocks are erased every 1008KB. None of the metadata values need to be modified in-place, so the read/erase/write-back process isn't required.

×
×
  • Create New...