Friday, July 25, 2014

CC3200 LaunchPad with external debugger and ARM GCC in Eclipse

Hot stuff! I got the board and read most of the the documentation, examples and APIs. It's time for debugging now. Since I don't like bulky SDKs that come for each eval board I tend to extract what I need from them (installing to virtual machine) and use external debugger. Modifications to connect external debugger are depicted below. No HW changes are needed on this one. TI made it all configurable with jumpers. There are 2 changes made:
  • SOP pins are configured to enable SWD (Single Wire Debug).
  • Debug lines are disconnected from on board FTDI debugger. External debugger is connected to freed debug pins via 3 lines SWDIO(TMS), SWDTCK(TCK) and GND. Let's not get into why 3 lines are needed for Single Wire Debug :).
I stopped boot in endless loop after connecting to it. I made simple while(1) empty loop project. Downloaded it to beginning of the RAM (0x20000000) and it worked.
I'm still not sure about clock settings. It doesn't seem that any PLL needs initializing...
I did sample project without any PLL code and it worked.

Also I didn't get SWO (Single Wire Output) to generate any output from ITM (Instrumentation Trace Macrocell). I know ITM was configured properly because it worked on some other devices. That only leaves IO configuration which I did with enabling GPIO3CLKEN clock, configuring corresponding GPIO_PAD_CONFIG_24 and set pin as output by setting GPIOA3[0]. Scope didn't show anything on TDO pin when writing ITM stimulus registers. Did anyone manage to get trace output ?
I added following code to initialize SWO pin without success:
PinModeSet(PIN_17, PIN_MODE_1);
PinDirModeSet(PIN_17, PIN_DIR_MODE_HW);
It works! Apparently TDO is not the pin to get SWO out. Pins 45, 53 and 50 are according to CC3200 forum. Anyway, connecting iTag to 53 and adding code below did the trick.
PinModeSet(PIN_53, PIN_MODE_13);


Created Eclipse C projects for CC3200 libs are available in repository. Short note for building: download CC3200 SDK separately (or extract from CCS installation). Library folders contain RefreshFiles.bat script invoked with CC3200 path to copy needed files to project folder.

While playing with integrated HTTP server I got frustrated with constant terminal to Uniflash tool UART switching. I decided to use UART Tx pin multiplexed with JTAG, which was not used since I'm using SWD.
To utilize it I added FTDI MM232R USB to serial module. I only connected CC3200 Tx to MM232R Rx for printf() tracing. Unconnected pin on LAUNCHPAD debug pinhead (J11) could be used for sending serial data to CC3200.
Code for UART initialization:
#define PIN_TERM_TX PIN_16
#define PIN_TERM_RX PIN_17


and code for sending single character:


CC3200-LAUNCHXL to MM232R closeup

Soon after I realized I can capture serial data with iTAG debugger since SWD leaves pins for capturing SWO and iTAG can be configured to dump UART data from that pin to terminal window.
CC3200-LAUNCHXL + iTAG with UART capturing

CC3200-LAUNCHXL + iTAG with UART capturing (iTAG closeup)

CC3200-LAUNCHXL + iTAG with UART capturing (LAUNCHPAD closeup)

Programming SPI flash without Uniflash through debug port

With setup above updating the SPI flash content still requires disconnecting the debug session, switching SOP jumper to 'FLASH' position and resetting the board to program files with TI Uniflash tool.

For development purposes I wrote small monitor application to run on CC3200 and Python script controlling the execution of the monitor through debugger to write files to SPI flash, e.g. write file data to CC3200 RAM and trigger function calling SimpleLink lib to write the data to file. Scripting is supported by winIDEA, IDE used with iTAG debugger and iSYSTEM.Connect API. My intention was to first format the flash and then program all files in specified folder. It turned out that formatting is not supported by library (only Uniflash tool). As workaround first SPI flash must be erased on low (SPI) level, then formatted with Uniflash tool and all data from flash read to be later used as "empty" image. This is done once. SPI access is provided in the script. Later on every update of the files the script erases the flash, programs "empty" image to it and then calls SimpleLink lib to create and write files. See script for more details.

Recording ITM printf() messages on SWO

Tested on pin 53 as mentioned in update above. Don't get confused by the photo below. I'm using white wire for SWO. SWO is configured by debugger to output at 4Mbits/second. CPU speed and SWO prescaler settings in winIDEA must be configured for this. Following equation applies: BAUD = CPUclk/(SWOprcs + 1) -> 80MHz/(19 + 1) = 4MHz.

White wire connected from pin 53 configured as SWO to TDO input on iTag

4M BAUD configured in winIDEA

Monday, July 21, 2014

Communication with embedded devices

It is always a hassle to communicate with embedded device. I do manage one time solution e.g. through USB to UART converter but it is always too much interleaved with application code to later switch to integrated USB peripheral.

Sometimes in the past I got requests to provide new or additional way of communication for device. Another use case I wrote this library for is when I found myself repeating writing same code. I had point to point serial communication implemented on some project. On another project I used serial bus approach (with CAN physical drivers - not important) and the communication was identical with addition of the byte header for destination address at the beginning of each packet. Repetition also happened on client and host side.

In short, Comm library offers a way to make communication entities modular thus easily replaceable. It also makes them stackable to make the whole through communication extending easy. First library implementation is in C [Google Code repository].

Communication is meant to be of  query - response from master (client) to slave (host). The use of library enforces a way of transmission and reception but the same design can be used on both sides of communication channel. This means that layer can have same implementation on client and host  side if both running on the same hardware platform.

From library point of view the communication entity is self sufficient communication layer implementing a set of predefined functions i.e. implementing an interface. As it turned out layers are of two types. In one stack there are more data formatting layers and single physical layer.

Physical layers are in charge of data storage and thus having communication buffer. Example of a layer on top of physical would be an encryption layer. Application interacts with Comm library functions when transferring data. Library then calls Comm layer implementation as needed. All functions have C++ style “this” pointer parameter. In the application accessible library functions this is a predefined Comm stack type holding a pointer to array of another predefined type instances each describing single Comm layer implementation. Comm layer instance is used as the "this" pointer in layer implementation functions and in library functions used for data transfer between layers. Comm layer instance has 5 pointers:
  • vague void pointer member to store reference to a custom type object for specific implementation
  • pointer to predefined type object holding function pointers of layer implementation
  • pointers to upper and lower layer if any
  • pointer to Comm stack to which layer belongs.

Instance custom pointer and pointer to functions are initialized in extra initialization function call which is custom for each specific layer implementation and additionally exposed to the application together with a custom instance type. This initialization function is not to be mistaken with layer implementation initialization function.
Pointers to surrounding layers and pointer to parent stack are initialized in library initialization call which should result in established connection after return.
Or everything again in objective language words: main communication stack object has methods for communication and holds references to layer objects each implementing the defined interface and custom init method which is only method called by application directly.
Below is a general sequence and internal states of the objects after each initialization step:

Initial state.

After first layer custom initialization call.

After last layer custom initialization call.

After Comm library initialization call.
Next to custom and implementation initialization method a Comm layer implements data transfer, event notification, and process methods.

Data transfer methods:

  • Send
    To send data in direction from application towards physical layer. Layer can optionally implement this method to transform data or add data to sent data. Additional data must be then in same fashion removed on receiving side in OnData call.

  • Store
    To save data in comm buffer. Called from OnData call back from upper layer. Usually only implemented in lowest, physical layer.

  • OnData
    To optionally unpack received data. Called from lower layer ReceiveProcess when new data received. Here is a chance to undo the changes to data made in Send and in PacketStart and in PacketEnd on transmitting side. If implemented it must forward remaining data with chained OnData call to upper layer or call Store if there is no upper layer like library does.

Event notifications:

  • PacketStart
    First call from application when sending a packet. Lower layers get this call first, upper last. Each layer can already put own header to transmitted packet with call to Send. This call gives layers a chance to clean up from previous application packet transfer. Send call(s) will follow.

  • PacketEnd
    Last call from application when sending a packet. Upper layers get this call first to append custom data to the packet with call to Send if needed. Physical layer can start actual transmission in this call.

  • OnNewPacket
    Call originates in physical layer ReceiveProcess method when start of new packet is detected. Here is a chance for layers to prepare for new packet. OnData call(s) will follow.

  • OnPacketEnd
    Called from physical layer ReceiveProcess  after complete packet was received.

Process methods:

  • TransmitProcess
    Called repeatedly from application after PacketEnd. Usually only implemented in physical layer. Returns Active status while data is being sent to medium and returns Idle status after all data is sent.

  • ReceiveProcess
    Called repeatedly from application to receive a packet. Usually only implemented in physical layer. Returns Idle status while there is no incoming data, optionally returns Active status while data is being received and returns NewPacket status after whole packet is received. Together with NewPacket status it returns the size of the packet and pointer to received data.

Flow of calls to send and receive the data with Comm library is as depicted below.

First call in client to send a packet to client; first call on host to send response.
PacketEnd behaves identically. Physical layer can start sending data in PacketEnd call.

Multiple calls to send data on client and host.

Multiple calls while transmitting data on client and host.

Repeatedly called on client while expecting a response from host; repeatedly called on host while waiting for new packet. OnPacketEnd behaves identically.

Repeatedly called on client while expecting a response from host; repeatedly called on host while waiting for new packet.
For test implementation I did a pair of embedded STM32F4 project and Windows client application communicating over USB. Windows side uses WinUSB library for communication and firmware reports a OS USB descriptor associating device with WinUSB driver so drivers or .inf files are not needed. Firmware code is in C and Windows client application uses C++ in Windows only code.

WinUSB communication with STM32 round 2 (Part 2: Client)

Previous client application is linked against WinUSB and SetupAPI libraries. This was a bit of a bother with WDK and project settings. They are loaded dynamically in new client test application. Two thin wrappers load the libraries and provide needed function calls with same prototypes as original library functions. SetupAPI is needed at low level for enumeration and when creating connection. WinUSB is further wrapped in an object representing USB device. And later wrapped in Comm interface explained in another post.
USB device object uses two USB pipes to transfer data which takes two USB endpoints in bulk mode at device side. One for sending data to device and other to receive it. Messaging control is done through USB control endpoint. Transfer sequence is optimized from previous implementation. Sending a complete application packet consists of sending a control message with the 32 bits length of the packet and then writing the packet data to bulk pipe. Receiving a packet is done with reading the return size through the control endpoint util nonzero length is returned and then reading the packet data from second endpoint. Application packet is meant to be a complete data set needed for single operation on device and can be larger than endpoint buffer.
Comm wrapper mentioned earlier is an implementation of the layer interface as specified by Comm library. Comm library core utilizes this interface to make transferring of data easier to application. WinUSB Comm layer is written to be the last layer in stack, also referred to as "physical" layer as is the closest to the physical medium on the master (client) side - Windows PC.
Application is written to test the connection and speed. Device is expected to return same data as sent by application. Speed is calculated from time it takes to send and receive back the packet.

Application uses Comm library methods to transfer the data. It is just that the Comm library object is initialized with comm layer using USB. It could instead be some other communication type, e.g. serial port or TCP/IP.

[Source files]

This is the second post in this series (of total 2 posts). See 1.