Teaching Precision Data Converters to speak Stellaris® Kevin Duke 1 Introduction • Why Stellaris? – StellarisWare is a helpful asset for quickly and easily delivering sample code with minimal experience on the platform – Stellaris evaluation boards have on-board emulation circuitry – 32 bit ARM Cortex M3 Core 2 Stellaris’ fit in the TI Embedded Portfolio 3 Stellaris’ fit in the TI Embedded Portfolio 4 Introduction • Why Code Composer Studio? – One of the many tool-chains that StellarisWare supports – Easy to use tools to view and export data in memory for analysis/evaluation – Dedicated internal support via the E2E Community 5 As simple as 7 lines of code... 6 ...and 5 blue wires DVDD DVDD VBD VDD ADS7953 CS SSI0Fss SDI SSI0Tx SDO SSI0Rx SCLK SSI0CLK BDGMD LM3S3748 GND DGND 7 Agenda • C Review • Code Composer Studio • Stellaris Peripherals • Creating Sample Code • Questions 8 C Review - Variable Types, Qualifiers, & Modifiers - StellarisWare variable naming convention - Function Prototypes & Definition 9 Variable Declaration & Qualifiers • <Qualifier/Modifier> <Type Modifier> <Type> <Name> • Common Qualifiers: – const indicates a structure or variable that contains a nonmodifiable run-time value – volatile indicates a structure or variable that is subject to sudden change and will be excluded from compiler optimization 10 Volatile Keyword Example tBoolean bNewData = FALSE; // Flag for new data while( !bNewData ) { //Do something else } 11 Volatile Keyword Example tBoolean bNewData = FALSE; // Flag for new data while( 1 ) { //Do something else } 12 Volatile Keyword Example Volatile tBoolean bNewData = FALSE; // Flag for new data while( !bNewData ) { //Do something else } 13 Variable Declaration & Modifiers • <Qualifier/Modifier> <Type Modifier> <Type> <Name> • Common Modifiers: – extern indicates that the initial value of a variable or body of a function is defined in another source file – static is typically used inside function calls and indicates that the structure or variable will only be initialized once and its value will be maintained even when it leaves scope 14 Variable Types & Type Modifiers • Basic Types: – char is an 8 bit fixed point allocation – int is usually a 16 bit fixed point allocation, but should be used with a type modifier for clarity – float is a 32 bit ‘single precision’ floating point allocation – double is a 64 bit ‘double precision’ floating point allocation • Type Modifiers: – – – – – signed indicates the data format is binary two’s complement unsigned indicates the data format is straight-binary short specifies a 16 bit allocation long specifies a 32 bit allocation or increases allocation size Note: unsigned short <name> is a valid declaration 15 tBoolean Type • Bool and Boolean are not keywords in standard C • tBoolean is an unsigned char typedef created and used heavily by StellarisWare • As a good rule of thumb always include inc/hw_types.h in source utilizing StellarisWare typedef unsigned char tBoolean; #ifndef true #define true 1 #endif #ifndef false #define false 0 #endif 16 Function Prototypes • Function prototypes tell the compiler what the function looks like and how it behaves • Function prototypes follow the pattern: – <Modifier> <Return Type> <Name>(<Parameters>); 17 Function Prototypes - Examples • void enablePeripheral(); - A generic enable function prototype that returns nothing and takes no parameters • signed short readData(); - A generic read function prototype that takes no parameters but returns a signed short • tBoolean writeData(signed short ssData); - A generic write function prototype that writes a signed short to the serial peripheral and returns a tBoolean indicating success or failure 18 StellarisWare Naming Convention • Variable types & return types are made clear in each declaration: – <type><Name> • Generic Examples: – – – – – unsigned short usVariable; unsigned long ulVariable; signed short ssVariable; signed long slVariable; unsigned char * pucVariable; 19 HWREG & Writing to Memory Directly • A series of HWREG macros are defined in hw_types.h along with the tBoolean declaration • HWREG() is a simple macro that type casts values appropriately to be treated as locations in memory – Used heavily by StellarisWare and looks scary, but is pretty simple 20 Code Composer Studio - Creating a Stellaris Project 21 Creating & Configuring a Stellaris Project • Create a New CCS Project • Add the Vector Table • Setup Compiler Include Paths • Setup Linker Search Paths • Pre-defined Symbols 22 Create a New Project • File > New > CCS Project 23 Create a New Project • CCS Generates: – Target configuration file for ICDI – Linker command file – Empty main file • What’s here will build cleanly, but it wont run 24 Creating & Configuring a Stellaris Project • Create a New CCS Project • Add the Vector Table • Setup Compiler Include Paths • Setup Linker Search Paths • Pre-defined Symbols 25 What is the NVIC? • Nested Vectored Interrupt Controller – Part of what makes the ARM Cortex M3! • The NVIC... – – – – – Enables / Disables interrupts Sets / Arbitrates interrupt priority Provides low-latency interrupt processing Works closely with the processor core for low-power modes Saves the processor state on entry to any given interrupt 26 What is the Vector Table? • Maps NVIC events to action carried out by interrupt service routines • The vector table always carries a unique name in each toolchain/IDE – In CCS it is called ‘startup_ccs.c’ • How to generate your own vector table – Copy & Paste a vector table from a sample StellarisWare project or use the one embedded in this slide – Create a new source file in CCS, name the file ‘startup_ccs.c’, paste the contents of the file embedded in this slide • If using a vector table from a StellarisWare project, make sure that it doesn’t have any un-needed or undefined ISR referenced startup_ccs.c 27 The Vector Table 28 Creating & Configuring a Stellaris Project • Create a New CCS Project • Add the Vector Table • Setup Compiler Include Paths • Setup Linker Search Paths • Pre-defined Symbols 29 Compiler Include Paths • The include paths tell the compiler where to look for files external to the CCS project (i.e. StellarisWare header files!) • Including source files in an include path does not mean that those files will be compiled when CCS builds the project • Project > Properties > Build > ARM Compiler > Include Options 30 Creating & Configuring a Stellaris Project • Create a New CCS Project • Add the Vector Table • Setup Compiler Include Paths • Setup Linker Search Paths • Pre-defined Symbols 31 Linker Search Path • Since included files are not compiled with the rest of the project when CCS builds the project – instead, pre-built libraries are provided for the linker to integrate with the project post-compile • Project > Properties > ARM Linker > File Search Path 32 Creating & Configuring a Stellaris Project • Create a New CCS Project • Add the Vector Table • Setup Compiler Include Paths • Setup Linker Search Paths • Pre-defined Symbols 33 Predefined Symbols • The StellarisWare API is usable by all Stellaris devices, symbol definition is used to help describe to StellarisWare the environment it is being used in • Generally there are 3 required definitions – IDE/Toolchain – Part Number – Device Family • Project > Properties > Build > ARM Compiler > Advanced Options > Predefined Symbols 34 Creating & Configuring a Stellaris Project • Create a New CCS Project • Add the Vector Table • Setup Compiler Include Paths • Setup Linker Search Paths • Pre-defined Symbols • Write Sample Code! 35 Code Composer Studio - Useful Tools 36 Watch Expressions • While debugging a project in CCSv5 any variable or data structure can be added to the ‘Watch Expression’ window to monitor it’s value • Highlight the variable, right-click, & select ‘Add Watch Expression’ 37 Graphing Tools • Sequential ranges of memory can be graphed & the graphing tool offers a variety of ways to look at the data – Assign data format, x-axis, address increment, etc. • Items in the Watch Expression window can be quickly graphed by selecting the item, right-click, and select ‘Graph’ – The graph assumes the data-format of the variable or structure being watched & sets address increment automatically 38 Other Useful Items • There are a lot of settings available for the compiler and linker in CCS, summary information is available to streamline debugging: – Project > Properties > ARM Compiler > Summary of Flags Set: • -mv7M3 --code_state=16 --abi=eabi -me -g -include_path="C:/TI/ccsv5/tools/compiler/tms470/include" --include_path="C:/StellarisWare" -define=ccs --define=lm3s3748 --define=TARGET_IS_DUSTDEVIL_RA0 --diag_warning=225 -display_error_number – Project > Properties > ARM Linker > Summary of Flags Set: • -mv7M3 --code_state=16 --abi=eabi -me -g --define=ccs --define=lm3s3748 -define=TARGET_IS_DUSTDEVIL_RA0 --diag_warning=225 --display_error_number -z -stack_size=256 -m"SummitDemo.map" --heap_size=0 -i"C:/TI/ccsv5/tools/compiler/tms470/lib" -i"C:/TI/ccsv5/tools/compiler/tms470/include" --reread_libs --warn_sections --rom_model • Compiler optimization is sometimes not ideal – Project > Properties > ARM Compiler > Optimization • Linker options are available to modify stack/heap size: – Project > Properties > ARM Linker > Basic Options 39 Stellaris Peripherals -GPIO Basics 40 Stellaris GPIO Essentials • Nearly all GPIO ports/pins are multiplexed with digital and peripheral functionality, by default GPIO are under “software control” • Each GPIO port under software control can be configured: – – – – – Input or Output Interrupt events Pull up/down resistors Open drain enables Drive strength (up to 18mA, limit 4 per device) • By default all GPIO, and many other peripherals use the Advanced Peripheral Bus (APB) bus 41 “Traditional” GPIO Data Access • What does the following line of code actually do? – ucSomeVariable |= 0x01; • Commonly referred to as read-modify-write access – ucSomeVariable = ucSomeVariable | 0x01; WRITE READ MODIFY 42 GPIO Bit Masking • Available for both read and write operations • Alleviates the need for read/modify/write access – increasing speed • Each data register is virtualized in 256 locations in the memory map, the address offset from the data address sets the bit mask 43 GPIO Bit Masking #defines resolved by pre-processor... HWREG(GPIO_PORTA_BASE + GPIO_O_DATA + ( GPIO_PIN_0 << 2) = 0x01; GPIO A Base Address GPIO A Data Address GPIO A Data Address with access only to bit 0 HWREG(0x40004000 + 0x00000000 + ( 0x00000001 << 2) = 0x01; macros evaluated by pre-processor... HWREG(0x40004004) = 0x01; Single action masked write (*((volatile unsigned long *)(0x40004004))) = 0x01; 44 Stellaris Peripherals -GPIO Acceleration for Parallel Interfaces 45 Accelerating GPIO for Parallel Buses • Always leverage the GPIO data bit masking features for read and write access • StellarisWare APIs are not ideal for controlling a high-speed parallel bus – LM3S3748 at 50MHz interfacing the AMC1210 parallel bus takes ~290 clock cycles to do a single byte select 16 bit read using StellarisWare • The APB is a congested bus since many peripherals use this bus 46 Accelerating GPIO for Parallel Buses • The Advanced High-Performance Bus (AHB) is less congested than the APB • AHB access in code behaves the same as using the APB aperture • Re-write versions of the StellarisWare read/write functions that do not do anything extra • LM3S3748 at 50MHz interfacing the AMC1210 parallel bus takes ~30 clock cycles to do a single byte select 16 bit read using HWREG and the AHB bus 47 Stellaris Peripherals -Synchronous Serial Interface for SPI Interfaces 48 Synchronous Serial Interface • Almost all Stellaris devices have the same SSI peripheral – SCLK: The maximum SCLK frequency is half the system clock or up to 25MHz in master mode – Frame Width: 4-16 Bit frames are supported, some can be combined for larger continuous frames – Frame Modes: TI SSI (Frame Sync), Motorola/Freescale SPI (Chip Select), and MICROWIRE (8-bit Half-Duplex) • Separate TX & RX FIFOs: – 16 Bits wide – 8 Locations deep 49 Back-to-Back Frames • 16 bits will only provide limited coverage over precision data converters • Frame combination is only allowed in Freescale SPI mode, and is limited by SSI clock phase 50 Creating Sample Code - ADS7953 ‘Case Study’ - Where to find digital answers in a Datasheet - Writing & Validating the Sample Code 51 Getting Started • Have documentation handy – Stellaris product datasheet • This Guide will use the LM3S3748 – Evaluation Board User’s Guide • Identify available clocking methods – Stellaris Peripheral Driver Library User’s Guide • Identify available functions and parameters of StellarisWare API • Create a Stellaris Project in Code Composer Studio – Everything is ready and we have a blank main.c • Include inc/hw_types.h in the project’s main 52 ADS7953 Evaluation Requirements • Defined by Part: – Frame Size – Framing Format – Critical Edge • Customer Requests – Select fastest SCLK possible w/LM3S3748 & ADS7953 – Operate ADS7953 in Manual Mode 53 As simple as 7 lines of code... 54 System Clock • Derivatives of the system clock will be used to clock every peripheral on the device • In documentation and StellarisWare the System Clock is a member of the System Control library – System Control also includes device identification, local control, lowpower modes, peripheral enables, and the on-chip LDO • Providing the system clock from the PLL source provides more flexibility than the other clocking options & achieves higher speed – The PLL VCO will be set very close to 400MHz, depending on crystal value – PLL VCO frequency is pre-divided to 200MHz, except for high-speed Stellaris products • Check if bit 30 (DIV400) in the RCC2 is reserved, this bypasses the predivider 55 Possible PLL Clocking Configurations • Check the ‘Clock Configuration’ subsection of ‘System Control’ in the product datasheet 56 Choosing the System Clock • Customer requests the highest speed possible w/LM3S3748 & ADS7953 • ADS7953 Max SCLK is 20MHz • The smallest clock divider from System Clock to SCLK is 2 – With a 50MHz system clock we must settle for 16.6MHz SCLK – If we settle for a 40MHz system clock we can achieve the max SCLK 57 Setting the System Clock • Include the appropriate driver for System Control from the StellarisWare library – driverlib/sysctl.h • All available functions of StellarisWare are documented in the Stellaris Peripheral Driver Library User’s Guide • void SysCtlClockSet(unsigned long ulConfig) – ulConfig is a 32 bit wide bit-field for passing values from the system control header of StellarisWare • To use the PLL ulConfig is made up of 4 values bitwise OR’d – – – – The external crystal frequency The clock divider setting SYSCTL_USE_PLL SYSCTL_OSC_MAIN 58 Values for SysCtlClockSet Parameters 59 As simple as 7 lines of code... 60 Enable GPIO & SSI Peripherals • Every peripheral in use needs to be enabled first • Enabling the SSI peripheral alone does not enable the physical port/pins in use on the device – The appropriate GPIO port must also be enabled • void SysCtlPeripheralEnable(unsigned long ulPeripheral) – ulPeripheral is the value from the system control header for the peripheral of interest 61 As simple as 7 lines of code... 62 Set GPIO Pin MUX • Almost every pin on every port can be set for two types of functionality – Digital I/O under software control – Hardware/Peripheral controlled • GPIO Port & Pin control are part of the GPIO driver of StellarisWare – #include “driverlib/gpio.h” • void GPIOPinTypeSSI(unsigned long ulPort, unsigned char ucPins) – ulPort is the base address of the GPIO port – ucPins is a bit field representative of the pins in use 63 Missing Peripheral Base Addresses • Identifier undefined almost always means an include file is missing • Peripheral base address values are defined in hw_memmap.h 64 As simple as 7 lines of code... 65 What is the Framing Format? • Chip Select (Motorola/Freescale) – Set for the entire frame • Frame Sync (TI)– Identifies the beginning of new data 66 Ask the Datasheet • What is the framing format? – Check the timing diagram – Check device pin configuration 67 Ask the Datasheet • How many bits per frame? – Check the Device Operation, Overview, and/or Digital Interface sections – Refer back to the timing diagram 68 Clock Phasing and Polarity • TI & Freescale SPI each have clock phase and polarity settings • Polarity describes what the clock looks like when the serial bus is idle • Polarity = 0 – The clock idles low • Polarity = 1 – The clock idles high 69 Clock Phasing and Polarity • Phase describes which clock edge will trigger reads and writes – Standard interfaces read and write on the same edge • Phase = 0 – Data is read/written on the first edge (Figure illustrated with Polarity 0) • Phase = 1 – Data is read/written on the second edge (Figure illustrated with Polarity 0) 70 Clock Phasing and Polarity • Phase and Polarity together define which edge is the critical edge – 2 ways to achieve each rising and falling critical edges 71 Clock Phasing and Polarity • Many devices do not specify clock polarity – i.e. ADS7953 • Only interested in seeing a rising or falling edge some time after CS has toggled 72 What is the Critical Edge? • The critical edge tells us when data may be changing and when data should be stable for reads & writes – Sets clock phase and polarity • MOSI – Master Out Slave In – Setup Time – How long the data needs to be valid before being clocked in – Hold Time – How long the data needs to remain valid to guarantee it is clocked in – Setup and Hold time on MOSI define the critical edge • MISO – Master In Slave Out – Delay Time – How long it takes for the data to settle on the bus – Hold Time – How long will the data remain on the bus 73 Ask the Datasheet • Do not just look at the timing diagram to find the critical edge • Look at MOSI (SDI) to discover the critical edge 74 Configuring the SSI Port • The SSI port can only be configured while peripheral operation is disabled • We’ve enabled clocking to the peripheral but it is still not operational – the StellarisWare API ensures peripheral operation is disabled when the peripheral clock is enabled • SSI control is in the SSI driver of StellarisWare – #include “driverlib/ssi.h” • void SSIConfigSetExpClk(...) – – – – – – unsigned unsigned unsigned unsigned unsigned unsigned long long long long long long ulBase – Base address of SSI Module ulSSIClk – Peripheral Clock Frequency ulProtocol – Specifies the interface protocol ulMode – Master or Slave mode ulBitRate – SCLK Frequency ulDataWidth – Number of bits per frame 75 As simple as 7 lines of code... 76 Interfacing the Data Converter • The LM3S3748 is fully configured and ready to interface the ADS7953 • Create a header file to represent the register settings of the device – Bit-field values like StellarisWare API parameters 77 Sending and Receiving Data • StellarisWare API provides blocking and non-blocking functions for both reads and writes – Blocking functions wait until there is space or new data in the TX or RX FIFOs to read data from memory – Non-blocking functions will simply not read or write data from memory if there is no space or nothing to read – Functions not marked “NonBlocking” are blocking • void SSIDataGet(unsigned long ulBase, unsigned long *pulData) – ulBase – Base address of the SSI port – *pulData – Pointer to the location in memory to store the data • Void SSIDataPut(unsigned long ulBase, unsigned long ulData) – ulBase – Base address of the SSI port – ulData – Data to be transmitted on the serial bus 78 Finishing Touches 79 Set Breakpoints, Debug, & Graph 80 For more information... • Embedded in this presentation are two CCSv5 projects – ADS7953 in Manual Mode w/StellarisWare – ADS7953 in Manual Mode w/StellarisWare w/DMA • Check out the Precision Data Converter Design Notes on the E2E Community – this presentation will be posted and updated to include interrupts, uDMA, and deeper coverage for each topic SummitDemo.zip SummitDemoDMA.zip 81