Wednesday, January 8, 2014

IAR kickstart dev kit for the LPC1788

Long story short I am working on my first commercial product and the lpc17xx series of cortex-m3 processors fits the bill.  Picked up this lpc1788 system on ebay for a whopping $47 + $16 = $63 verses the 399.99 it used to cost new. Board appears to power up - comes with JLINK lite for debugging ... Heres a breakdown and pics


LPC1788-SK evaluation board
Microcontroller
  • LPC1788FBD208 LQFP

User interfaces
  • 2x user buttons
  • LCD 3.5’’ 320x200 24bit color TFT with backlight and touch screen

Debug interfaces

  • JTAG/SWD connector - 20 pin 0.1’’
  • SWD connector - small 9 pin 0.05’’
  • ETMv3 connector - small 19 pin 0.05’’

Communication interfaces
  • RS232/ICSP
  • USB host and OTG
  • CAN driver and connector
  • IrDA
  • 100 Mbit Ethernet 12C routed to connector
  • UXT connector
  • EXT connector
  • QEI connector

Power functions
  • Multiple power supply options:
    - J-Link (pin 19)
    - Trace connector (pin 11&13)
    - External supply
  • Power supply LED

Additional features
  • Audio in and out
  • SD/MMC card connector
  • Trimpot
  • Accelerometer

Schematic for download (PDF)

J-Link Lite for ARM
J-Link Lite for ARM is a small JTAG/SWD hardware debug probe; it connects via USB to the PC host running Windows.
 






Thursday, November 21, 2013

the sort of bugs that keep you up at night - ripping your hair out

Ok so I figured Id test this $50 investment real quick, before I get back to work I am doing with the Xilinx Xcv3 Spartan board. Figured Id modify the my stm32 firmware/linker scripts for the different I/O ports on this board. Figured Id get it to where I was originally with USB access - didnt think it would take three days ...

I had encountered a serious error right off the bat. Where the code was generating hard faults with fault #3 in execution and systick handler #15 pending and never running (after the first time).

The cortex m3 pushes 8 registers on the stack whenever it takes an exception. So I modified stm32_nvic_fault_handler as follows

asm ("mrs r0, msp");
asm ("ldr   r1, [r0, #24]");

The value returned was something like 0x2000 0887. Checked the map file flash.map and found that was a line of code in the stm32_uart_puts() routine. I tried to disassemble it from within gdb and it balked after address 0x2000 0888.

I used monitor mdw 0x20000888 3 to look at the three words immediately after loading the file "load" and before setting a break point and running to main. I noticed that the value was changing when I got to main ... it made no sense.


I started to wonder why the stack (monitor reg sp) held a value other than the 0x20010000 I wanted it set to. After all the first instruction in main was forcing the stack with

asm ("ldr sp, =(0x20000000 + (64 * 1024) - 4)");

Thats when I noticed that when arm-linux-gnueabi-gdb ./usb_test.out runs it prints out

xPSR: 0x01000000 pc: 0x0800125 msp: 0x20000890

Where was it getting this value? The command
monitor reset halt
Should be placing it in a known state. But where was that. I checked the map file and found nothing that would lead me to believe it was using information I provided. I checked the openocd scripts for odd initialization parameters.

Then I remember that on the arm7 board I had a similar problem because the board would start up running from flash. So when I dumped the value of 0x0 it was 0x2000 0890.

EUREKA!!!

Jtag still allows it to boot from eeprom on reset before it grabs control and the stack value was corrupting my program in ram.

So the solution would have to be the same I did with the arm7 and other cortex-m3. I will wipe out the contents of flash.

I did it with.

monitor flash probe 0
monitor flash protect 0 0 127 off
monitor reset halt
monitor stm32f1x mass_erase 0
monitor flash protect 0 0 127 on 
 

Now arm-linux-gnueabi-gdb ./usb_test.out starts off with

xPSR: 0x01000000 pc: 0xfffffffe msp: 0xfffffffc

No where near my program at ram address 0x2000 0000 (64k of it on this ZET)



No more hard faults and my systick stay-alive-LED blinks once a second. Next Ill tackle uart and usb  ... if I have time













I purchased The Definitive Guide To Arm cortex-m3 this morning as well. It should shed a little more light on some gotchas - not necessarily listed or described well in the arm cortex m3 and the stm32 manuals

STM32F103ZET6 ARM Cortex-M3 Development Board

STM32F103ZET6(development board ) with FSMC,NAND/NOR FLASH 
STM32 development board based on STMicroelectronics (ST) has introduced the highest series of ARM CortexM3 chip configuration as the core component STM32F103ZET6
On-board resources:
* CPU: STM32F103ZET6; (LQFP144-pin, on-chip integrated 512K flash, 64KRAM, 12Bit A / D, D / A; PWM, CAN, USB, SDIO, FSMC and other resources)
* Outside the expanded board 512K SRAM, 2M NOR FLASH (on-board support for the largest 1024k SRAM, 16M of NOR FLASH) to meet the large capacity data acquisition, processing and analysis requirements
 

* Board outside 128M NAND FLASH expand to meet the rich color of the picture storage, data storage form, document management applications and so on
*FSMC control, color touch module configuration TSC2046 controller, support for a SD card (SPI mode) can be used to store pictures, in support of AT45DBxxx of a DATA FLASH (can be used for storage)
 

* All the way CAN communication interface, the drive chip SN65VHD230

* Two-way RS232 interface
 

* All the way RS485 communication interface

* A SD card connector SDIO control

* A I2C memory interface, the standard 24LC02 (EEPROM)

* A SPI memory interface, AT45DB161D or M45PE16V (DATA FLASH)
* All the way adjustment potentiometer ADC input

* Three-way leads to ADC input terminals

* Two-way terminal block PWM output leads

* Two-way leads to DAC output terminals
* A buzzer, the five users LED lights, a power indicator light, a USB communication indicator, four user keys, a system reset button
 * Power Select jumper to support the external 5V power supply, USB power supply or power supply by JLINK
* Board Size: 13CM X 10CM 




Tuesday, November 12, 2013

[peekstm32] the problem was data toggle

The odd thing was that the problem lay with JUST the peek function or host "IN" packets. I played around with the stm32_endp_isr_user_out() routines "IN" packet handling section. Wasnt sure of the state of DTOG_TX so I figured Id force it to 0 instead 1.

Immediately the first peek command from the next run worked and failed there after. After playing around with DTOG_TX forced to 1, toggled I finally deleted it, essentially leaving it floating and that worked

Basically delete this line from stm32_endp_isr_user_out()
        stm32_usb_set_epr_dtog(wdEndP,\
                               1,\
                               STM32_USB_EPR_DTOG_TX_OFFSET);


End Result - arm m-3 minicom:
--------RESET----------- 27uS
--------RESET----------- 28uS
80 06 00 01 00 00 40 00
--------RESET----------- 28uS
00 05 3E 00 00 00 00 00
usb device address = 3E
80 06 00 01 00 00 12 00
80 06 00 02 00 00 09 00
80 06 00 02 00 00 20 00
80 06 00 03 00 00 FF 00
80 06 02 03 09 04 FF 00
80 06 01 03 09 04 FF 00
80 06 03 03 09 04 FF 00
00 09 01 00 00 00 00 00
00 08 ED FE 04 5C 00 40
user req peek   [40005C04]=7021
00 08 ED FE 04 5C 00 40
user req peek   [40005C04]=3061
00 08 ED FE 04 5C 00 40
user req peek   [40005C04]=7021
00 08 ED FE 04 5C 00 40
user req peek   [40005C04]=3061
00 08 ED FE 40 60 00 40
user req peek   [40006040]=00
01 0C ED FE 40 60 00 40
user req poke   [40006040]=B0
00 08 ED FE 40 60 00 40
user req peek   [40006040]=B0



On the host linux pc side:
sudo ./peekstm32.out 0x40005c04
[40005c04] = 7021
sudo ./peekstm32.out 0x40005c04
[40005c04] = 3061
sudo ./peekstm32.out 0x40005c04
[40005c04] = 7021
sudo ./peekstm32.out 0x40005c04
[40005c04] = 3061
sudo ./peekstm32.out 0x40006040
[40006040] = 0
sudo ./peekstm32.out 0x40006040 0xb0
sudo ./peekstm32.out 0x40006040
[40006040] = b0

DONE!!!

Monday, November 11, 2013

[peekstm32] libusb_bulk_transfer() command failed with -7

/usr/include/libusb-1.0/libusb.h lists -1 as
LIBUSB_ERROR_TIMEOUT = -7,

But timeout is set to 1000ms or 1 second in my peekstm32.c program. My primary concern is that I am not seeing any communication on the stm32 side with bulk endpoints. Need to check their configuration settings in the EPRX registers later.

I am seeing this now ... but the problem persists EVEN though the usb sniffer clearly shows data transmission without any errors, with peek and pokes from peekstm32.c


using linux libusb to test communication with the my stm32 firmware

Figured Id put together a small example program to allow me to test out my usb device/firmware by using usb communication (on the linux host) to peek and poke offsets in stm32 space. Culminating in toggling LED1 off and on from the linux host.

With that in mind I installed libusb
apt-cache search libusb
apt-get install libusb-1.0.0 libusb-1.0.0-dev

And wrote peekstm32.c
usage is a follows:
[peekstm32]    options
                        adddress value[optional]


But it seemed to be failing on the libus_claim_device() routine. Thats also when I discovered that not all the configuration data had been transferred.
lsusb -vvv -dc0de: returns

Bus 001 Device 013: ID c0de:feed 
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.10
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0         8
  idVendor           0xc0de
  idProduct          0xfeed
  bcdDevice            1.00
  iManufacturer           1 Igbo Embedded
  iProduct                2 My Device
  iSerial                 3 1234
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           32
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0
    bmAttributes         0xc0
      Self Powered
    MaxPower              500mA
Device Status:     0x0000
  (Bus Powered)



The Interface and Endpoint descriptors are missing. Also I noticed on the minicom usb communication dump that the linux host send two get configuration descriptor commands. one for 9 bytes the other for 32 so the first succeeds (IN) but the second fails:

80 06 00 02 00 00 09 00
80 06 00 02 00 00 20 00

Need to look at this closely before continuing with the userland program. Found the problem - bug on line 825 of IE_stm32_usb.c: Removed this line

                        if(wdSize > (*ptrTemp))
                                wdSize  = (*ptrTemp);


And  all is well. I actually found that bug by placing tclib_printf() of wdCount inside stm32_dequeue_IN_transfers.

Now
sudo lsusb -dc0de: -vvv returns

Bus 001 Device 017: ID c0de:feed 
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.10
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0         8
  idVendor           0xc0de
  idProduct          0xfeed
  bcdDevice            1.00
  iManufacturer           1 Igbo Embedded
  iProduct                2 My Device
  iSerial                 3 1234
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           32
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0
    bmAttributes         0xc0
      Self Powered
    MaxPower              500mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      0 No Subclass
      bInterfaceProtocol      0 None
      iInterface              0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval               2
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x01  EP 1 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval               2
Device Status:     0x0000
  (Bus Powered)










peekstm32.c

/*
 ***********************************************************************
 *name:         peekstm32
 *author:       Samuel Igwe
 *date:         11/11/2013 A.D
 *description:  stm32 host to usb peek and poke routine. 
 *note:         peekstm32 address               = read address
 *              peekstm32 address  value        = write value to address
 *compiled as:  gcc -o peekstm32.out -lusb-1.0  linux/peekstm32.c
 ***********************************************************************
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <libusb-1.0/libusb.h>



/*#define constants*/
#define STMUSB_VENDOR_ID                                0xc0de
#define STMUSB_PRODUCT_ID                               0xfeed

#define STMUSB_BULK_ENDP_OUT                            0x1
#define STMUSB_BULK_ENDP_IN                             0x81

#define STMUSB_CMD_PEEK                                 0
#define STMUSB_CMD_POKE                                 1

#define STMUSB_TIMEOUT                                  1000



/*structure*/
struct  STR_PEEKSTM32
        {
        unsigned int                    wdAddress;
        unsigned int                    wdValue;
        unsigned int                    wdMaxPktSize;
        
        struct  libusb_device_handle    *ptrHandle;
        struct  libusb_device           *ptrDevice;

        }strPeekStm32;



void    func_atexit(void);



/*
 ***********************************************************************
 *description:  main routine    
 *inputs:       int     argc    = count
 *              char    *argv[] = pointer to command line parameters
 ***********************************************************************
 */
main(int argc, char *argv[])
{
unsigned int    wdCount, wdTemp;
         char   sbBuffer[64];
/*
 ***********************************************************************
 *check commandline parameters
 ***********************************************************************
 */
memset(&strPeekStm32, 0, sizeof(strPeekStm32));
switch(argc)
        {
        case    2:
        case    3:
                {
                strPeekStm32.wdAddress = \
                (unsigned int)strtol(argv[1], (char **)NULL, 16);
                if(argc == 3)
                        {
                        strPeekStm32.wdValue = \
                        (unsigned int)strtol(argv[2], (char **)NULL, 16);
                        }

                break;
                }
        default:
        case    0:
        case    1:
                {
                printf("[peekstm32]\toptions\n\t\tadddress value[optional]\n");
                return 0;
                }
        }



/*
 ***********************************************************************
 *initialize variables and atexit routine
 ***********************************************************************
 */
if(atexit(func_atexit) != 0)
        {
        printf("[peekstm32]\tatexit() failed\n");
        return 0;
        }       



/*
 ***********************************************************************
 *initialize library
 ***********************************************************************
 */
if((wdTemp = libusb_init(NULL)) != 0)
        {
        printf("[peekstm32]\tlibusb_init() failed with %d\n",\
               wdTemp);
        return 0;
        }

if((strPeekStm32.ptrHandle=libusb_open_device_with_vid_pid(NULL,\
                                   STMUSB_VENDOR_ID,\
                                   STMUSB_PRODUCT_ID)) == NULL)
        {
        printf("[peekstm32]\tlibusb_open_device_vid_pid() failed\n");
        return 0;
        }

if((strPeekStm32.ptrDevice = libusb_get_device(strPeekStm32.ptrHandle)) == NULL)
        {
        printf("[peekstm32]\tlibusb_get_device() failed\n");
        return 0;
        }

if((wdTemp = libusb_kernel_driver_active(strPeekStm32.ptrHandle, 0)) !=0)
        {
        if((wdTemp = libusb_detach_kernel_driver(strPeekStm32.ptrHandle, 0)) !=0)
                {
                printf("[peekstm32]\tlibusb_detach_kernel_driver() failed with %d\n",\
                       wdTemp);
                return 0;
                }
        }
else
        {
        if((wdTemp = libusb_claim_interface(strPeekStm32.ptrHandle, 0)) != 0)
                {
                printf("[peekstm32]\tlibusb_claim_interface() failed with %d\n",\
                       wdTemp);
                return 0;
                }
        }



/*
 ***********************************************************************
 *get usb resources limits
 ***********************************************************************
 */
strPeekStm32.wdMaxPktSize = 0;
for(wdCount=0; wdCount < 16; wdCount++)
        {
        wdTemp = libusb_get_max_packet_size(strPeekStm32.ptrDevice, wdCount);
        if(wdTemp != LIBUSB_ERROR_NOT_FOUND && wdTemp != LIBUSB_ERROR_OTHER)
                strPeekStm32.wdMaxPktSize = wdTemp;
        }


if(strPeekStm32.wdMaxPktSize <8)
        {
        printf("[peekstm32]\tlibusb_get_max_packet_size() failed to return adequate value\n");
        return;
        }



/*
 ***********************************************************************
 *execute OUT transaction:COMMAND format is as follows:
 *      byte    0       = command
 *      byte    1       = length of data in bytes
 *      byte    2       = 0xed
 *      byte    3       = 0xfe
 *      byte    4       = 32bit address
 *      byte    5       = 
 *      byte    6       = 
 *      byte    7       = 
 ***********************************************************************
 */
if(argc == 2)                                   /*IN*/
        {
        sbBuffer[0] = STMUSB_CMD_PEEK;
        sbBuffer[1] = 8;                        /*8*/ 
        }
else
        {
        sbBuffer[0] = STMUSB_CMD_POKE;
        sbBuffer[1] = 12;                       /*8 + 4 byte (dword)value*/
        }
sbBuffer[2] = 0xed;
sbBuffer[3] = 0xfe;
memcpy(sbBuffer+4, &strPeekStm32.wdAddress, sizeof(int));

wdTemp = libusb_bulk_transfer(strPeekStm32.ptrHandle,\
                              STMUSB_BULK_ENDP_OUT,\
                              sbBuffer,\
                              8,\
                              &wdCount,\
                              STMUSB_TIMEOUT);
if(wdTemp != 0)
        {
        printf("[peekstm32]\tlibusb_bulk_transfer() command failed with %d\n",\
               wdTemp);
        return 0;
        }



/*
 ***********************************************************************
 *execute IN or OUT transaction depending on whether PEEK or POKE sought
 ***********************************************************************
 */
if(argc == 2)                                   /*IN*/
        {
        if((wdTemp =libusb_bulk_transfer(strPeekStm32.ptrHandle,\
                                STMUSB_BULK_ENDP_IN,\
                                (char *)&(strPeekStm32.wdValue),\
                                4,\
                                &wdCount,\
                                STMUSB_TIMEOUT)) != 0)
                {
                if(wdCount == 0)
                        {
                        printf("[peekstm32]\tlibusb_bulk_transfer() data failed with %d\n",\
                               wdTemp);
                        return 0;
                        }
                }

        printf("[%x] = %x\n", strPeekStm32.wdAddress,\
                              strPeekStm32.wdValue);
        return 0;
        }
else                                            /*OUT*/
        {
        memcpy(sbBuffer, &strPeekStm32.wdValue, sizeof(int));
        if((wdTemp = libusb_bulk_transfer(strPeekStm32.ptrHandle,\
                                STMUSB_BULK_ENDP_OUT,\
                                (char *)&(strPeekStm32.wdValue),\
                                4,\
                                &wdCount,\
                                STMUSB_TIMEOUT)) != 0)
                {
                printf("[peekstm32]\tlibusb_bulk_transfer() data failed with %d\n",\
                       wdTemp);
                return 0;
                }
        }



/*
 ***********************************************************************
 *atexit
 ***********************************************************************
 */
return 0;
}





/*
 ***********************************************************************
 *description:  at exit routine
 ***********************************************************************
 */
void    func_atexit(void)
{
if(strPeekStm32.ptrHandle != NULL)
        {
        libusb_release_interface(strPeekStm32.ptrHandle, 0);
        libusb_close(strPeekStm32.ptrHandle);
        }

return;
}