dev builds
themes manual
device status forums
mailing lists
IRC bugs
dev guide

Search | Go
Wiki > Main > PortingHowTo > PortingHowToIMX233

How to Create a New Build Target For the i.MX233


The i.MX233 port handles the following families of chips:
  • i.MX233 from Freescale, which is a rebranded Sigmatel STMP3780
  • STMP3700 from Sigmatel, which handles STMP37xx chips with xx < 70
  • STMP3600 from Sigmatel, which handles all STMP36xx chips

These chips are very complex and the port provides many facilities to avoid writing code or simplify the drivers. Following PortingHowTo, all the new files should be in the direction firmware/arm/imx233/mydap/ where mydap is the name of the new target.

Configuration File

Be sure to read PortingHowToConfigFile? before reading this. Like for other targets, you should create a configuration file in firmware/export/config/ and include it in firmware/target/config.h. In addition to the many standard defines, you must define the following:
  • IMX233_SUBTARGET is the chip id
  • IMX233_PACKAGE is the chip package
  • IMX233_PARTITIONS is the partition scheme used


The IMX233_SUBTARGET will condition every driver of the imx233 tree, so be sure to get it right. There are mostly three possibilities:
  • 3600 for STMP3600 family (actually you can use value between 3600 and 3699)
  • 3700 for STM37000 familiy (3700-3799)
  • 3780 for the STMP3780/i.MX233

#define IMX233_SUBTARGET    3700


The IMX233_PACKAGE will condition a number of standard pins. At the moment, only BGA169 is supported even though many values are defined:
  • IMX233_BGA169 for the BG169 package
  • IMX233_BGA100
  • IMX233_TQFP100
  • IMX233_TQFP128
  • IMX233_LQFP100

#define IMX233_PACKAGE      IMX233_BGA169


On most targets, the storage layer provides access to the whole disc but part of it is reserved for firmware and system. The partition schemes tells the code what is the scheme used to hide this and provide a view of the user data only. It is handled by firmware/target/imx233/partition-imx233.c and new scheme might be added in the future. The possible values are:
Currently the scheme applies to all disks with some restritions (see section on storage).


Freescale Partition Scheme (ATA/SD/MMC)

On those target, Freescale uses a root MBR with four partitions: one firmware (type 53), two system and one logical (type 5). The logical one is the actual partition shown to the user. It needs to be handle specially because the type 5 is not normally used for logical partition and thus not understand by any OS.

Creative Partition Scheme

Creative uses a very weird scheme with a proprietary partition table called the MBLK. It is located at a fixed address in the drive (which can be changed in the partition driver) and provide named entries. The usual entries are:
  • minifs for the firmware partition, using the MiniFS? file system
  • cfs for the user partition, using the CFS file system.
Rockbox currently uses the cfs partition and you need to reformat it to FAT.

Button driver

Be sure to read PortingHowToButtonDriver? before reading this. The button driver should be named button-mydap.c and you must provide an header named button-target.h. The imx233 provides code for common cases such as:
  • touchscreen/touchpad using the LRADC controller: use touchscreen-imx233.c
  • buttons using the LRADC controller: use button-lradc-imx233.c
  • buttons using PSWITCH: use imx233_power_read_pswitch
These to do provide an actual driver but a framework to simplify them so that in most cases you don't have to write anything nontrivial.

Note that your driver can use a combination of some, even all the driver. For example, on the SamsungZ5, the inner button are on a touchpad, reading using the touchscreen driver while the outer buttons are read using LRADC and the power button is read using PSWITCH. You can also implement others buttons on top of this using other means like GPIOs or i2c touchpad/touchscreen controllers.


If your target has a touchscreen or touchpad wired to the LRADC controller (usually it's a 4 wire touchscreen), you can make sure of the touchscreen-imx233.c driver. In order to properly use it, you must:
  • call imx233_touchscreen_init and imx233_touchscreen_enable(true) in button_init_device
  • use imx233_touchscreen_enable to enable/disable it in touchscreen_enable_device or touchpad_enable_device
  • use imx233_touchscreen_get_touch in button_read_device to get the raw value
There are a couple things worth mentionned:
  • the touchscreen driver is generic and does not force you define HAVE_TOUCHSCREEN. For example you can define a touchpad and use the touchscreen driver to read the values and translate them in the driver.
  • imx233_touchscreen_get_touch can be called from any context and only returns a cached value. The driver is completely asynchronous.
  • the touchscreen driver can only detect one finger.

void button_init_device(void)
    // blabla

static int touch_to_pixels(int *val_x, int *val_y)
    // for you to implement: does raw value -> pixel translation

void touchscreen_enable_device(bool en)

static int touchscreen_read_device(int *data)
    int x, y;
    if(!imx233_touchscreen_get_touch(&x, &y))
        return 0;
        *data = touch_to_pixels(&x, &y);
    return touchscreen_to_pixels(x, y, data);

int button_read_device(int *data)
    int res = 0;
    /* read other buttons */
    return res | touchscreen_read_device(data);

Resistor Ladders / ADC buttons

If your target implements some buttons using a resistor ladder and a voltage plugged into the LRADC, you can use the button-lradc-imx233.c driver which already implements all the boring stuff such as proper lradc config, debouncing and so on. Of course it needs a few defines and init. You are advised to read button-lradc-imx233.h and you must:
  • define IMX233_BUTTON_LRADC_CHANNEL in button-target.h, it is the LRADC channel on which it is plugged, usually it's 0
  • define IMX233_BUTTON_LRADC_HOLD_DET in button-target.h if your target has HOLD detect. See below
  • define an array called imx233_button_lradc_mapping in button-mydap.c which in sorted by increasing values and gives the expected reading for each of the button. It should always end with an entry {0, IMX233_BUTTON_LRADC_END}

If your target has HOLD detect, you must define HAS_BUTTON_HOLD in button-target.h like for any target and you must tell the driver how to detect it. It supports several methods controlled by IMX233_BUTTON_LRADC_HOLD_DET:
  • BLH_ADC: HOLD is read like a regular key and you must have an entry in imx233_button_lradc_mapping for it, with the key set to IMX233_BUTTON_LRADC_HOLD
  • BLH_GPIO: HOLD is read on a GPIO, in which case you must provide the bank and the pin using BLH_GPIO_BANK and BLH_GPIO_PIN. If it needs a pullup, define BLH_GPIO_PULLUP and if it's inverted, define BLH_GPIO_INVERTED.
  • BLH_EXT: the driver won't detect HOLD and you must implement it yourself in a function called imx233_button_lradc_hold

On top of that, you driver must do a few calls:
  • call imx233_button_lradc_init in button_init_device
  • call imx233_button_lradc_read(btn) in button_read_device. The btn argument should be the bitmask of all others key which are not read by the LRADC. These will be ignored if HOLD is on (as reported by LRADC/GPIO or imx233_button_lradc_hold), and if HOLD is off, these will be ORed will the key detect by the driver.
  • call imx233_button_lradc_hold in button_hold

For debug purposes and calibration, the driver provides a imx233_button_lradc_read_raw function which gives you the raw LRADC value.

/* in button-target.h */
#define BLH_GPIO_BANK   0
#define BLH_GPIO_PIN    9

/* in button-mydap.c */
struct imx233_button_lradc_mapping_t imx233_button_lradc_mapping[] =
    {1095, BUTTON_BACK},
    {1470, BUTTON_PLAY},
    {1845, BUTTON_RIGHT},
    {2185, BUTTON_LEFT},
    {2525, BUTTON_UP},
    {2870, BUTTON_DOWN},
    {3400, 0},

void button_init_device(void)

bool button_hold(void)
    return imx233_button_lradc_hold();

int button_read_device(void)
    int res = 0;
    if(imx233_power_read_pswitch() == 3)
        res |= BUTTON_POWER;
    return imx233_button_lradc_read(res);


If you need the PSWITCH value, you can call imx233_power_read_pswitch which will provide you with it.

if(imx233_power_read_pswitch() == 1)
        btn |= BUTTON_POWER;

FM Radio

Be sure to read PortingHowToFMRadio? before reading this. If your target uses has a FM tuner, you will need to provide a few functions for the driver to work: mostly i2c routines and tuner power. These are usually boring to write so you can use the fmradio-imx233.c driver to simplify most of it. Of course it needs a few defines. You are advised to read fmradio-imx233.h and you must put all the defines into fmradio-target.h. You can also optionally add some code into fmradio-mydap.c for unsupported functionality like RDS which is not handled by this driver. You must define:
  • IMX233_FMRADIO_I2C is the i2c driver to use
  • IMX233_FMRADIO_POWER controls how the tuner power is handled.

At the moment, there are two i2c drivers:
  • FMI_HW uses the hardware i2c (you can use the hardware but cannot controls the pins)
  • FMI_SW use the generic software i2c and you must define the pins to use using FMI_SW_SDA_BANK, FMI_SW_SDA_PIN, FMI_SW_SCL_BANK and FMI_SW_SCL_PIN.

There also are two methods to controls the tuner power:
  • FMP_NONE means the tuner power cannot be controlled
  • FMP_GPIO means it is controlled by a GPIO and you must define FMP_GPIO_BANK and FMP_GPIO_PIN. In case the pin is inverted, define FMP_GPIO_INVERTED. You can also specify a power-up delay by defining FMP_GPIO_DELAY in ticks.

Note that the fmradio-imx233.c driver will completely implement tuner_power and fmradio_i2c_{read,write} so you don't need and must not write wrappers for them.

#define IMX233_FMRADIO_I2C  FMI_SW
#define FMI_SW_SDA_BANK     1
#define FMI_SW_SDA_PIN      24
#define FMI_SW_SCL_BANK     1
#define FMI_SW_SCL_PIN      22

#define FMP_GPIO_BANK   0
#define FMP_GPIO_PIN    29
#define FMP_GPIO_DELAY  (HZ / 10)

Power Management

Be sure to read PortingHowToPowerManagement? before reading this. The imx233 features a very complex power management unit implemented in powermgmt-imx233.c and it should not be attempted to alter its behaviour. Instead, the driver relies on the existence on a few defines in powermgmt-target.h:
  • IMX233_CHARGE_CURRENT is the charging current in mA, usually between 100mA and 300mA
  • IMX233_STOP_CURRENT is the stop current in mA, usually charge current divided by 10
  • IMX233_CHARGING_TIMEOUT is the timeout before stopping the charger in ticks, usually 4h
  • IMX233_TOPOFF_TIMEOUT is the timeout before exiting the topoff state in ticks, usually 30min

#define IMX233_CHARGE_CURRENT   200
#define IMX233_STOP_CURRENT     30
#define IMX233_TOPOFF_TIMEOUT   (30 * 60 * HZ)
#define IMX233_CHARGING_TIMEOUT (4 * 3600 * HZ)

Audio Driver

Be sure to read PortingHowToAudio? before reading this. The handling of audio in Rockbox is pretty complicated, being spread accross many areas such as codecs, routing and gating. For this reason, it is recommended to always use the audio-imx233.c driver and the corresponding imx233-codec.c codec. These drivers will take care of the gory details about the builtin codec. You are advised to read audio-imx233.h. In order to work correctly, you must always define in audio-target.h:
  • IMX233_AUDIO_COUPLING_MODE is the audio coupling mode of the headphones, it can be ACM_CAPLESS or ACM_CAP

You can optionally define many more parameters:
  • IMX233_AUDIO_HP_GATE_BANK and IMX233_AUDIO_HP_GATE_PIN if the headphones are protected by a gate. Define IMX233_AUDIO_HP_GATE_INVERTED if it's inverted
  • IMX233_AUDIO_SPKR_GATE_BANK and IMX233_AUDIO_SPKR_GATE_PIN if the speaker is protected by a gate. Define IMX233_AUDIO_SPKR_GATE_INVERTED if it's inverted.

Alternatively, you can override the weak implementation of some audio functions by reimplementing:
  • imx233_audio_preinit does the preinit and it's default behaviour is to init the headphones and speaker gates (if any)
  • imx233_audio_postinit does the postinit and usually enables the headphones by default
  • imx233_audio_enable_hp enables or disable the headphones and it's default behaviour is to use a GPIO gate (if any)
  • imx233_audio_enable_spkr does the same for the speaker
And if you are really mad, you can even override the low level functions, but this is not recommended.
  • audio_input_mux for input audio mux
  • audio_set_output_source for output audio source

There are a few things to note about the driver:
  • if you defined a FM tuner, the driver will assume it is routed to Line1
  • if you defined a microphone, the driver will assume it is biaised using LRADC channel 1 and at the moment you cannot change the resistor and the biais

#define IMX233_AUDIO_HP_GATE_BANK   1
#define IMX233_AUDIO_HP_GATE_PIN    30

#define IMX233_AUDIO_SPKR_GATE_PIN  22


-- AmauryPouly - 25 Nov 2013
r6 - 28 Nov 2013 - 21:43:23 - AmauryPouly

Parents: PortingHowTo
Copyright by the contributing authors.