Showing posts with label M3. Show all posts
Showing posts with label M3. Show all posts

Tuesday, April 17, 2012

WinUSB communication with STM32 (Part 1: Intro)

Aren't you fed up with putting a USB to serial converter in your embedded design while you have a USB capable device already in the design? Any other approach opens a can of worms though. Custom driver, certificate to sign it, USB vendor ID (2000$ at the moment), how to communicate with device on a layer above USB? But it is nice when OS pops up your name when your device is plugged in USB port. WinUSB is middle ground with tradeoffs one might consider.

I wanted to test the use of WinUSB with STM32F103 for some time now. When I finally got time I created a demo project. It shows basic request - response communication.
WinUSB kernel mode driver enables raw communication through USB pipes. In other words you can communicate with your USB device directly from application on the PC. So there is only code for application and code for firmware. Presuming you are not making standard USB class device like Mass Storage or HID. You might not even need custom PC side software in this case.
Furthermore the libraries to communicate are written for both ends to some extent. There SetupAPI and WinUSB on Windows side while ST has libraries for everything.
To get a taste check images below. I will post more about it in the future and probably publish the sources after I clean and organize them.

VS showing sent data.

winIDEA showing same received data on STM32.

This is the first post in this series (of total 4 posts). See  234.

[Update - I have a new WinUSB device project with STM32F407 without the need for Windows side driver info (.inf and .cat files) ]


Sunday, April 8, 2012

LCD Type On Cheap STM32 Camera Board From eBay

I bought a camera board with 2.8 inch TFT LCD and STM32 on eBay for 50 bucks some time ago. The primary project was put aside after I lost my initial excitement and motivation. After almost a year I was organizing libraries from ST for STM32 for some other purposes. I came across GUI library and remembered that I have the board laying around and decided to test the GUI library.


STM32 camera board (SWD debugging; I rewired the uSD  soon after I bought it)
Circle on functional LCD at the end (original FW displayed the picture from camera)
LCD connection - it is a 37pin connector

Soon I discovered that there are no usable markings for the LCD. I got the schematic from the seller and the demo project sources which were zipped in password protected archive. Nothing found with Google had any LCD type information. I had no way to determine how to set up the communication with the LCD. I didn't decide to query the seller for the password due to his lag in replying - I waited a week to get the mentioned files when I bought the board.
I assumed that the design is based on a evaluation board from ST. There are drives in ST libraries for the LCDs that ST uses on their boards.
Luckily I still have the original firmware (binary file only) to see how the LCD is used. I have programmed it and set up my debugger (winIDEA - I use iSystem emulator) to break on access to registers for the port to which LCD was connected. Fortunately only one port is used for LCD (PORTB). After each RUN the application stopped on each IO port signal change and I could read the signals values.

Watchpoint breakpoints setup in winIDEA
Port registers display in winIDEA

To automate the process of running, waiting to stop and reading the value I wrote a Python script. It uses the exposed API called "isystem.connect" for controlling/interfacing the winIDEA.
Obtained values exposed the LCD initialization sequence from the ST library for SPFD5408.

Ptyhon script:
import isystem.connect as ic
from isystem.connect import IConnectDebug as ICDebug

    
def toHEX8(val):
  return '0x{0:02X}'.format(val)

def toDEC(val):
  return '{0: 3d}'.format(val)

class LCDInterafceValues:
  def __init__(self):
    self.data = 0
  def setNewValues(self, pinsValues):
    self.data = pinsValues
  def isnCS(self):
    return (self.data & (1<<12)) != 0
  def isRS(self):
    return (self.data & (1<<13)) != 0
  def isnWR(self):
    return (self.data & (1<<14)) != 0
  def isnRD(self):
    return (self.data & (1<<15)) != 0
  def getnCS(self):
    if (self.data & (1<<12)) != 0: return 1
    else: return 0
  def getRS(self):
    if (self.data & (1<<13)) != 0: return 1
    else: return 0
  def getnWR(self):
    if (self.data & (1<<14)) != 0: return 1
    else: return 0
  def getnRD(self):
    if (self.data & (1<<15)) != 0: return 1
    else: return 0
  def getData(self):
    return self.data & 0xFF
  def printHeader(self):
    print "CS  RS  RD  WR  data"
  def printLevels(self):
    if self.isnCS(): print "#  ",
    else: print "|  ",
      
    if self.isRS(): print "#  ",
    else: print "|  ",
  
    if self.isnRD(): print "#  ",
    else: print "|  ",
  
    if self.isnWR(): print "#  ",
    else: print "|  ",
      
    print toHEX8(self.getData()),
    print toDEC(self.getData())
    
cmgr = ic.ConnectionMgr()       # Create a connection manager
cmgr.connectMRU()               # Connect to the last used instance of winIDEA

debug = ic.CDebugFacade(cmgr)   # Create a debug object for the connected winIDEA 
debug.reset()                   # Reset CPU

pv = LCDInterafceValues()       # Create a value parser helper
pv.printHeader()

# Watchpoints have already been set in dialogs in winIDEA
# Just run until a watchpoint is hit, then read the IO levels  
while True:
  debug.run()                   # Run the CPU
  debug.waitUntilStopped()      # Do nothing while the CPU is running
  
  # Evaluate expression. Any C expression with firmware variables would be valid here.
  # '@' prefix tells winIDEA to evaluate (read from memory) a peripheral register.
  PortBPins = debug.evaluate(ICDebug.fMonitor , "@GPIOB_IDR").getInt()
  pv.setNewValues(PortBPins);   # Give the IO port value to helper
  pv.printLevels()              # Display values
 
 
Console output ( '#' means signal is HIGH and '|' that is LOW):
CS  RS  RD  WR  data
#   #   #   #   0x12  18
#   #   #   #   0x12  18
#   #   #   #   0x12  18
#   #   #   #   0x12  18
#   #   #   #   0x12  18
#   |   #   #   0x12  18
|   |   #   #   0x12  18
|   |   #   |   0x12  18
|   |   #   #   0x00   0
|   |   #   |   0x00   0
|   |   #   #   0xE3  227
#   |   #   #   0xE3  227
#   |   #   #   0xE3  227
#   #   #   #   0xE3  227
|   #   #   #   0xE3  227
|   #   #   |   0xE3  227
|   #   #   #   0x30  48
|   #   #   |   0x30  48
|   #   #   #   0x08   8
#   #   #   #   0x08   8
#   #   #   #   0x08   8
#   |   #   #   0x08   8
|   |   #   #   0x08   8
|   |   #   |   0x08   8
|   |   #   #   0x00   0
|   |   #   |   0x00   0
|   |   #   #   0xE7  231
#   |   #   #   0xE7  231
#   |   #   #   0xE7  231
#   #   #   #   0xE7  231
|   #   #   #   0xE7  231
|   #   #   |   0xE7  231
|   #   #   #   0x00   0
|   #   #   |   0x00   0
|   #   #   #   0x12  18
#   #   #   #   0x12  18
#   #   #   #   0x12  18
#   |   #   #   0x12  18
|   |   #   #   0x12  18
|   |   #   |   0x12  18
|   |   #   #   0x00   0
|   |   #   |   0x00   0
|   |   #   #   0xEF  239
#   |   #   #   0xEF  239
#   |   #   #   0xEF  239
#   #   #   #   0xEF  239
|   #   #   #   0xEF  239
|   #   #   |   0xEF  239
|   #   #   #   0x12  18
|   #   #   |   0x12  18
|   #   #   #   0x31  49
#   #   #   #   0x31  49
#   #   #   #   0x31  49



Wednesday, November 30, 2011

Odd/even value for Cortex M3 reset vector

After reset the CM3 loads it's startup address from address 0x00000004.
The value at that location should be odd (LSB set) denoting the thumb destination. All exception and interrupt vectors following reset vector should be odd.
The reset vector might not have the LSB set by the linker. This is when reset handler code is written in assembler.
It's label is usually used in exception handlers table, but the linker doesn't know that this is a THUMB function address, so it doesn't change the value in exception table. It actually shouldn't since it could be a label of some data table used elsewhere - linker doesn't know anything about exception table either!
We need to tell the linker that some label is a THUMB function. GCC provides '--thumb-entry' command line switch to tell the linker about this one function but I couldn't get it to work. What helped was marking the label as THUMB function with '.type' and/or '.thumb_func' directive - depends on the GCC build/version you are using.


.type Reset, %function
.thumb_func
Reset:
  <code here>

To have some other function exported and available for linkage also add .global for the symbol:

.global Reset