The STM32 and IPod Remote Source Code




Knowing that the serial parameters should be 19200 baud , 8 data bits and 1 stop bit, no parity the first task was to grab some samples of the Usart data stream and in doing so we find similar results to that found in the site referenced earlier.

  0 1 2 3 4 5 6 7 8
 Left Pressed
 FF 55 06 02 00 10 00 00 00
 Right Pressed
 FF 55 06 02 00 08 00 00 00
 + Pressed
 FF 55 06 02 00 02 00 00 00
 - Pressed
 FF 55 06 02 00 04 00 00 00
 Play Pressed
 FF 55 06 02 00 01 00 00 00
 Any Key Released
 FF 55 06 02 00 00 00 00 00

Each Data packet recorded is shown above. The general data packet structure is shown below. We find that the payload data length is always 6 bytes for this particular maxell ipod remote and it's mode is 0x02 which is the code for a simple IPod remote control.

Maxell IPod remote data packet:

  
 Header 1
 FF
 Header 2
 55
 Payload Length
 06
 Mode 02
  00
 Key Code
 XX
  00
  00
 End 00

IPod Remote modes:

 0 Mode Switching
 1 IPod Voice Recording
 2 Simple IPod Remote
 4 Advanced IPod Remote (Air)

The Third byte of the payload data contains the key code we are interested in while the rest are always zero, The data packets are repeated when the key is held down and when any key is released a single data packet with the keycode set to zero is sent.

Maxell IPod remote Key-codes:

0x01 Play
0x02 Vol  Plus +
0x04 Vol Minus -
0x08 Track Forward Right
0x10 Track backwards Left


The example program uses usart2 for output to a terminal program , if you need a some good terminal software try the open source RealTerm which is ideal for micro-controller projects. The terminal should be set to 11500 baud, 8 bits, 1 stop bit, no parity. Usart 1 is used to receive the IPod remote control data stream and only RX is enabled on GPIOA 10.

The Source code is shown below in its entirety, it is also available as an attachment at the bottom of the page.

First the gpio, rcc , usart and misc include files need to be uncommented in stm32f10x_conf.h


/* Includes ------------------------------------------------------------------*/
/* Uncomment the line below to enable peripheral header file inclusion */
/* #include "stm32f10x_adc.h" */
/* #include "stm32f10x_bkp.h" */
/* #include "stm32f10x_can.h" */
/* #include "stm32f10x_cec.h" */
/* #include "stm32f10x_crc.h" */
/* #include "stm32f10x_dac.h" */
/* #include "stm32f10x_dbgmcu.h" */
/* #include "stm32f10x_dma.h" */
/*#include "stm32f10x_exti.h"*/
/* #include "stm32f10x_flash.h" */
/* #include "stm32f10x_fsmc.h" */
#include "stm32f10x_gpio.h"
/* #include "stm32f10x_i2c.h" */
/* #include "stm32f10x_iwdg.h" */
/* #include "stm32f10x_pwr.h" */
#include "stm32f10x_rcc.h"
/* #include "stm32f10x_rtc.h" */
/* #include "stm32f10x_sdio.h" */
/* #include "stm32f10x_spi.h" */
/* #include "stm32f10x_tim.h" */
#include "stm32f10x_usart.h"
/* #include "stm32f10x_wwdg.h" */
#include "misc.h"  /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */


Main.c , here ipod_remote_update()does the main work in reading a byte from the remote control data stream and synchronises to the header bytes 0xFF 0x55 , it then takes the third data byte as the key-code and skips the remaining bytes.If no byte is available from the remote control or it has not yet found the key-code then the function returns -1 and we continually poll the routine for a positive value that is the key-code.




/**
*    main.c
*
*    STM32 Discovery IPod remote control interface example code
*
*    Copyright (C) 2010  nano-age.co.uk
*
*    This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation, either version 3 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*
**/


#include <stdio.h>
#include "stm32f10x.h"

/* IPod remote keycode defines */

#define IPOD_REMOTE_KEY_PLAY 0x01
#define IPOD_REMOTE_KEY_PLUS 0x02
#define IPOD_REMOTE_KEY_MINUS 0x04
#define IPOD_REMOTE_KEY_LEFT 0x10
#define IPOD_REMOTE_KEY_RIGHT 0x08

/* Prototypes */

void printkey(int key);
int ipod_remote_update();
int usart1_testchar();
void usart1_init(USART_InitTypeDef* USART_InitStruct);
void usart2_init(USART_InitTypeDef* USART_InitStruct);


/* IPod remote main program */

int main(void) {

    USART_InitTypeDef USART_InitStructure;

    //by default stdin/stdout are on usart2 we will use 115200 baud
    USART_InitStructure.USART_BaudRate = 115200;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl
            = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    usart2_init(&USART_InitStructure);

    // only change needed for ipod remote on usart1 is the baud rate of 19200 baud and Rx only
    USART_InitStructure.USART_Mode = USART_Mode_Rx ;
    USART_InitStructure.USART_BaudRate = 19200;
    usart1_init(&USART_InitStructure);

    // turn off buffers, so IO occurs immediately
    setvbuf(stdout, NULL, _IONBF, 0);
    iprintf("IPod remote control demo\n");

    int lastkey = -1;
    while (1) {

        int key = ipod_remote_update();
        if (key != -1) {
            if (key == lastkey) {
                if (key != 0) {
                    // key repeat
                    printkey(key);
                    printf(" repeated\n");
                }
            } else {
                if (key == 0) {
                    //key released
                    printkey(lastkey);
                    printf(" released\n");
                } else if (lastkey == 0) {
                    //key pressed
                    printkey(key);
                    printf(" pressed\n");
                }
            }
            lastkey = key;
        }
    }
}


/*
 * Simple state based poll routine to test for an ipod remote key press
 *
 * Returns
 * 0 : key released
 * -1 : no key press or release on this call
 * xx : ipod remote keycode
 */
#define IPOD_REMOTE_LOOK 0
#define IPOD_REMOTE_SYNC 1
#define IPOD_REMOTE_GETBYTES 2
#define IPOD_REMOTE_SCAN 3

int ipod_remote_state = IPOD_REMOTE_SYNC;
int ipod_remote_bytes;
int ipod_remote_count;
int ipod_remote_checksum;
int ipod_remote_key;

int ipod_remote_update() {
    int c = usart1_testchar();
    if (c != -1) {
        switch (ipod_remote_state) {
        case IPOD_REMOTE_LOOK:
            if (c == 0xFF)
                ipod_remote_state = IPOD_REMOTE_SYNC;
            break;
        case IPOD_REMOTE_SYNC:
            if (c == 0x55)
                ipod_remote_state = IPOD_REMOTE_GETBYTES;
            break;
        case IPOD_REMOTE_GETBYTES:
            ipod_remote_bytes = c;
            ipod_remote_state = IPOD_REMOTE_SCAN;
            ipod_remote_count = 0;
            ipod_remote_checksum = c;
            break;
        case IPOD_REMOTE_SCAN:
            ipod_remote_count++;
            ipod_remote_checksum += c;
            if (ipod_remote_count > ipod_remote_bytes) {
                ipod_remote_state = IPOD_REMOTE_LOOK;
                // checksum should be 0x100 so only return the key if it is otherwise ignore
                if (ipod_remote_checksum == 0x100)
                    return ipod_remote_key;
            } else if (ipod_remote_count == 3) {
                ipod_remote_key = c;
            } else {
                // ignore
            }
            break;
        }
    }
    return -1; // no key was found this time
}

/* Print the IPod remote control key name to stdout */
void printkey(int key) {
    switch (key) {
    case 0:
        printf("none");
        break;
    case IPOD_REMOTE_KEY_LEFT:
        printf("left");
        break;
    case IPOD_REMOTE_KEY_RIGHT:
        printf("right");
        break;
    case IPOD_REMOTE_KEY_PLUS:
        printf("plus");
        break;
    case IPOD_REMOTE_KEY_MINUS:
        printf("minus");
        break;
    case IPOD_REMOTE_KEY_PLAY:
        printf("play");
        break;
    }
}

/* The Usart init routines */

void usart1_init(USART_InitTypeDef* USART_InitStruct) {

    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);

    /* Configure USART Rx as input floating */
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* USART configuration */
    USART_Init(USART1, USART_InitStruct);

    /* Enable USART */
    USART_Cmd(USART1, ENABLE);

}

void usart2_init(USART_InitTypeDef* USART_InitStruct) {

    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
    /* Configure USART Tx as alternate function push-pull */
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* Configure USART Rx as input floating */
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* USART configuration */
    USART_Init(USART2, USART_InitStruct);

    /* Enable USART */
    USART_Cmd(USART2, ENABLE);

}

/*
 * Test for a character on USART1
 *
 * Returns -1 if none available , else the character code
 */

int usart1_testchar() {
    if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET)
        return -1;
    return (uint16_t)(USART1->DR & (uint16_t) 0x01FF);
}





ċ
Atom Age,
19 Nov 2010, 05:29
Comments