/* ********************************************************************** *name: stmusb_test.c *author: Samuel Igwe *date: 08/12/2013 *description: stm32 usb test code. ********************************************************************** */ #include "IE_stm32.h" #include "IE_tclib.h" /*#include "usb_test.h"*/ /* ********************************************************************** *mappings *PA0 = external wire jumpered to usb d+ ********************************************************************** */ #define USB_TEST_GPIO_PIN_USB STM32_GPIO_PIN_USB #define USB_TEST_GPIO_PIN_DELAY 5000 #define USB_TEST_GPIO_PIN_CONNECT_CHAR 'c' #define USB_TEST_GPIO_PIN_DISCONNECT_CHAR 'd' /* ********************************************************************** *macros ********************************************************************** */ void usb_test_user_connect(void); #define STMUSB_SHOW_TIME(ptrString) \ { \ stmlib_printf("%x\t", stm32_get_seconds);\ stmlib_printf("%s\n", ptrString); \ } /* ********************************************************************** *description: main() function * this is where it all happens ********************************************************************** */ int main() { /* ********************************************************************** *stm32_init() initialization ... must be called first *stm32_usb_init() initialization ********************************************************************** */ stm32_init(); stm32_usb_init(); stm32_systick_hook_services(usb_test_user_connect); stm32_usb_disconnect_pullup(USB_TEST_GPIO_PIN_USB); stm32_timer_uS_delay(250000); stm32_usb_connect_pullup(USB_TEST_GPIO_PIN_USB); /* ********************************************************************** *now loop forever ********************************************************************** */ while(1) ; return 0; } /* ********************************************************************** *description: used to check for rx value 'c'|'C' which is a trigger * to call stm32_usb_connect_pullup() *inputs: none ********************************************************************** */ void usb_test_user_connect(void) { volatile unsigned int wdTemp; /* ********************************************************************** *check the uart rx read status *retrieve the data ********************************************************************** */ wdTemp = (*PTR_STM32_UART1_SR); if((wdTemp & STM32_UART_SR_RXNE) != STM32_UART_SR_RXNE) return; wdTemp = (*PTR_STM32_UART1_DR); wdTemp &= 0x1ff; switch(wdTemp) { case USB_TEST_GPIO_PIN_CONNECT_CHAR: { tclib_printf("-------user-usb-connect----request------\n", 0); stm32_usb_connect_pullup(USB_TEST_GPIO_PIN_USB); break; } case USB_TEST_GPIO_PIN_DISCONNECT_CHAR: { tclib_printf("-------user-usb-disconnect-request------\n", 0); stm32_usb_disconnect_pullup(USB_TEST_GPIO_PIN_USB); break; } default: break; } }
Wednesday, August 28, 2013
usb_test.c
IE_stm32_usbdev.h
/* ********************************************************************** *name: IE_stm32_usbdev.h *author: Samuel Igwe *date: 08/27/2013 *description: IE_stm32_usbdev usb device header ********************************************************************** */ #ifndef IE_STM32_USB_DEV #define IE_STM32_USB_DEV /* ********************************************************************** *usb control and user endpoint (interrupt) ********************************************************************** */ #define STMUSB_ENDP_CTRL_NUM 0 #define STMUSB_ENDP_CTRL_SIZE 8 #define STMUSB_ENDP_CTRL_MAX_SIZE 64 #define STMUSB_ENDP_USER_NUM 1 #define STMUSB_ENDP_USER_SIZE 8 #define STMUSB_ENDP_INT_INTERVAL 2 /* ********************************************************************** *descriptor type ********************************************************************** */ #define USBDEV_DESCR_TYPE_DEVICE 1 #define USBDEV_DESCR_TYPE_CONFIGURATION 2 #define USBDEV_DESCR_TYPE_STRING 3 #define USBDEV_DESCR_TYPE_INTERFACE 4 #define USBDEV_DESCR_TYPE_ENDPOINT 5 #define USBDEV_DESCR_TYPE_DEV_QUALIFIER 6 #define USBDEV_DESCR_TYPE_OTHER_SPEED_CONFIG 7 #define USBDEV_DESCR_TYPE_INTERFACE_POWER 8 #define USBDEV_DESCR_TYPE_OTG 9 #define USBDEV_DESCR_TYPE_DEBUG 10 #define USBDEV_DESCR_TYPE_INTERFACE_ASSOC 11 /* ********************************************************************** *usb class code ********************************************************************** */ #define USBDEV_CLASS_CODE_AUDIO 0x01 #define USBDEV_CLASS_CODE_COMM 0x02 #define USBDEV_CLASS_CODE_HID 0x03 #define USBDEV_CLASS_CODE_PHYSICAL 0x05 #define USBDEV_CLASS_CODE_IMAGE 0x06 #define USBDEV_CLASS_CODE_PRINTER 0x07 #define USBDEV_CLASS_CODE_STORAGE 0x08 #define USBDEV_CLASS_CODE_HUB 0x09 #define USBDEV_CLASS_CODE_DATA 0x0a #define USBDEV_CLASS_CODE_CARD 0x0b #define USBDEV_CLASS_CODE_SECURITY 0x0d #define USBDEV_CLASS_CODE_VIDEO 0x0e #define USBDEV_CLASS_CODE_PERSONAL 0x0f #define USBDEV_CLASS_CODE_AUDIO_VIDEO 0x10 #define USBDEV_CLASS_CODE_DIAGNOSTIC 0xdc #define USBDEV_CLASS_CODE_WIRELESS 0xe0 #define USBDEV_CLASS_CODE_APPLICATION 0xfe #define USBDEV_CLASS_CODE_VENDOR_SPECIFIC 0xff /* ********************************************************************** *usb requests ********************************************************************** */ #define USBDEV_REQ_GET_STATUS 0 #define USBDEV_REQ_CLEAR_FEATURE 1 #define USBDEV_REQ_SET_FEATURE 3 #define USBDEV_REQ_SET_ADDRESS 5 #define USBDEV_REQ_GET_DESCRIPTOR 6 #define USBDEV_REQ_SET_DESCRIPTOR 7 #define USBDEV_REQ_GET_CONFIGURATION 8 #define USBDEV_REQ_SET_CONFIGURATION 9 #define USBDEV_REQ_GET_INTERFACE 10 #define USBDEV_REQ_SET_INTERFACE 11 #define USBDEV_REQ_SYNTH_FRAME 12 /* ********************************************************************** *transfer type request related #defines ********************************************************************** */ #define USBDEV_CONFIG_DESC_ATTR_BUS (1 << 7) #define USBDEV_CONFIG_DESC_ATTR_SELF (1 << 6) #define USBDEV_CONFIG_DESC_ATTR_REMOTE_WAKE (1 << 5) #define USBDEV_ENDP_DESC_ADDR_DIR_IN (1 << 7) #define USBDEV_ENDP_DESC_ADDR_DIR_OUT (0 << 7) #define USBDEV_ENDP_DESC_ATTR_CTRL 0 #define USBDEV_ENDP_DESC_ATTR_ISOCHRONOUS 1 #define USBDEV_ENDP_DESC_ATTR_BULK 2 #define USBDEV_ENDP_DESC_ATTR_INTERRRUPT 3 /* ********************************************************************** *8 byte setup packet offsets ********************************************************************** */ #define USBDEV_SETUP_REQTYPE_OFFSET 0 #define USBDEV_SETUP_REQTYPE_DIR_H_TO_D (0 << 7) #define USBDEV_SETUP_REQTYPE_DIR_D_TO_H (1 << 7) #define USBDEV_SETUP_REQTYPE_DIR_MASK (1 << 7) #define USBDEV_SETUP_REQTYPE_TYPE_STANDARD (0 << 5) #define USBDEV_SETUP_REQTYPE_TYPE_CLASS (1 << 5) #define USBDEV_SETUP_REQTYPE_TYPE_VENDOR (2 << 5) #define USBDEV_SETUP_REQTYPE_TYPE_RESERVED (3 << 5) #define USBDEV_SETUP_REQTYPE_TYPE_MASK (3 << 5) #define USBDEV_SETUP_REQTYPE_DEST_DEVICE 0 #define USBDEV_SETUP_REQTYPE_DEST_INTERFACE 1 #define USBDEV_SETUP_REQTYPE_DEST_ENDPOINT 2 #define USBDEV_SETUP_REQTYPE_DEST_OTHER 3 #define USBDEV_SETUP_REQTYPE_DEST_MASK 0x1f #define USBDEV_SETUP_REQUEST_OFFSET 1 #define USBDEV_SETUP_VALUE_OFFSET 2 #define USBDEV_SETUP_INDEX_OFFSET 4 #define USBDEV_SETUP_LENGTH_OFFSET 6 /* ********************************************************************** *string descriptors *offset 1 = manufacturers string *offset 2 = product string *offset 3 = serial number * *swStrDescr below is an array of 4 of: pointer ********************************************************************** ********************************************************************** *string descriptor is unicode (16 bits) *string descriptor is 2*strlen(ptrDescStr)+2 bytes ********************************************************************** */ static unsigned char ptrStr0[]={ (4), /*byte length of descriptor*/ USBDEV_DESCR_TYPE_STRING, /*string descriptor type*/ 0x9, /*english code*/ 0x4}; /*english subcode*/ static unsigned char ptrStr1[]={ ((13 << 1)+2), /*byte length of descriptor*/ USBDEV_DESCR_TYPE_STRING, /*string descriptor type*/ 'I',0,'g',0,'b',0,'o',0,' ',0,\ 'E',0,'m',0,'b',0,'e',0,'d',0,'d',0,'e',0,'d',0}; static unsigned char ptrStr2[]={ ((9 << 1)+2), /*byte length of descriptor*/ USBDEV_DESCR_TYPE_STRING, /*string descriptor type*/ 'M',0,'y',0,' ',0,\ 'D',0,'e',0,'v',0,'i',0,'c',0,'e',0}; static unsigned char ptrStr3[]={ ((4 << 1)+2), /*byte length of descriptor*/ USBDEV_DESCR_TYPE_STRING, /*string descriptor type*/ '1',0,'2',0,'3',0,'4',0}; static unsigned int swUsbDevDescr[]={(unsigned int)ptrStr0,\ (unsigned int)ptrStr1,\ (unsigned int)ptrStr2,\ (unsigned int)ptrStr3}; /* ********************************************************************** *device descriptor ********************************************************************** */ static const char sbDevDescr[]={ 18, /*byte length of descriptor*/ USBDEV_DESCR_TYPE_DEVICE, /*device descriptor type*/ 0x10, /*bcd usb version 1.1 = word*/ 0x01, 0, /*device class*/ 0, /*device subclass*/ 0, /*device protocol*/ STMUSB_ENDP_CTRL_SIZE, /*max packet size*/ 0xde, /*vendor id = word*/ 0xc0, 0xed, /*device id = word*/ 0xfe, 0x0, /*bcd device = word*/ 0x1, 1, /*manufacturer descriptor string*/ 2, /*product descriptor string*/ 3, /*serial descriptor string*/ 1}; /*number of configurations*/ /* ********************************************************************** *configuration descriptor ********************************************************************** */ static const char sbConfDescr[]={ 9, /*byte length of descriptor*/ USBDEV_DESCR_TYPE_CONFIGURATION, /*configuration descriptor type*/ (9+9+7+7), /*total lenght = word*/ 0, 1, /*number of interfaces*/ 1, /*configuration value id*/ 0, /*configuration descriptor string*/ (USBDEV_CONFIG_DESC_ATTR_SELF | \ USBDEV_CONFIG_DESC_ATTR_BUS), /*bus attributes*/ 250, /* ************************************************************** *interface descriptor ************************************************************** */ 9, /*byte length of descriptor*/ USBDEV_DESCR_TYPE_INTERFACE, /*interface descriptor type*/ 0, /*interface number - zero based*/ 0, /*alternate setting*/ 2, /*number of endpoints*/ USBDEV_CLASS_CODE_HID, /*human interface device*/ 0, /*interface subclass*/ 0, /*interface protocol*/ 0, /*interface descriptor string*/ /* ************************************************************** *endpoint descriptor - input ************************************************************** */ 7, /*byte lenght of descriptor*/ USBDEV_DESCR_TYPE_ENDPOINT, /*endpoint descriptor type*/ (USBDEV_ENDP_DESC_ADDR_DIR_IN |\ STMUSB_ENDP_USER_NUM), /*endpoint in*/ USBDEV_ENDP_DESC_ATTR_INTERRRUPT, /*attributes*/ STMUSB_ENDP_USER_SIZE, /*packet length = word*/ 0, STMUSB_ENDP_INT_INTERVAL, /*interrupt interval*/ /* ************************************************************** *endpoint descriptor - output ************************************************************** */ 7, /*byte lenght of descriptor*/ USBDEV_DESCR_TYPE_ENDPOINT, /*endpoint descriptor type*/ (USBDEV_ENDP_DESC_ADDR_DIR_OUT |\ STMUSB_ENDP_USER_NUM), /*endpoint in*/ USBDEV_ENDP_DESC_ATTR_INTERRRUPT, /*attributes*/ STMUSB_ENDP_USER_SIZE, /*packet length = word*/ 0, STMUSB_ENDP_INT_INTERVAL}; /*interrupt interval*/ #endif
Monday, August 26, 2013
IE_stm32_timer.h
/* ********************************************************************** *name: IE_stm32_timer.h *author: Samuel Igwe *date: 08/27/2013 *description: Igbo Embedded stm32_timer header ********************************************************************** */ #ifndef IE_STM32_TIMER #define IE_STM32_TIMER #define PTR_STM32_TIM2_BASE 0x40000000 #define PTR_STM32_TIM3_BASE 0x40000400 #define PTR_STM32_TIM4_BASE 0x40000800 #define PTR_STM32_TIM5_BASE 0x40000c00 /* ********************************************************************** *timer #defines *basic timers 6 and 7 arent supported on the stm32f103. but general *purpose timers 2 through 5 are supported * *these timers are driven off a 36Mhz clock (sysclk / 2) which is the *maximum on the APB1 bus ********************************************************************** ********************************************************************** *control register 1 ********************************************************************** */ #define PTR_STM32_TIM2_CR1 (volatile unsigned int *)(PTR_STM32_TIM2_BASE + 0x0) #define PTR_STM32_TIM3_CR1 (volatile unsigned int *)(PTR_STM32_TIM3_BASE + 0x0) #define PTR_STM32_TIM4_CR1 (volatile unsigned int *)(PTR_STM32_TIM4_BASE + 0x0) #define PTR_STM32_TIM5_CR1 (volatile unsigned int *)(PTR_STM32_TIM5_BASE + 0x0) #define STM32_TIM_CR1_CKD_MASK (0x3 << 8) #define STM32_TIM_CR1_CKD_TCK (0 << 8) #define STM32_TIM_CR1_CKD_2TCK (1 << 8) #define STM32_TIM_CR1_CKD_4TCK (2 << 8) #define STM32_TIM_CR1_ARPE (1 << 7) #define STM32_TIM_CR1_CMS_MASK (0x3 << 5) #define STM32_TIM_CR1_CMS_EDGE (0 << 5) #define STM32_TIM_CR1_CMS_MODE1 (1 << 5) #define STM32_TIM_CR1_CMS_MODE2 (2 << 5) #define STM32_TIM_CR1_CMS_MODE3 (3 << 5) #define STM32_TIM_CR1_DIR_MASK (1 << 4) #define STM32_TIM_CR1_DIR_UP (0 << 4) #define STM32_TIM_CR1_DIR_DOWN (1 << 4) #define STM32_TIM_CR1_OPM (1 << 3) #define STM32_TIM_CR1_URS (1 << 2) #define STM32_TIM_CR1_UDIS (1 << 1) #define STM32_TIM_CR1_CEN (1 << 0) /* ********************************************************************** *control register 2 ********************************************************************** */ #define PTR_STM32_TIM2_CR2 (volatile unsigned int *)(PTR_STM32_TIM2_BASE + 0x4) #define PTR_STM32_TIM3_CR2 (volatile unsigned int *)(PTR_STM32_TIM3_BASE + 0x4) #define PTR_STM32_TIM4_CR2 (volatile unsigned int *)(PTR_STM32_TIM4_BASE + 0x4) #define PTR_STM32_TIM5_CR2 (volatile unsigned int *)(PTR_STM32_TIM5_BASE + 0x4) #define STM32_TIM_CR2_MMS_TI1S (0x1 << 7) #define STM32_TIM_CR2_MMS_MASK (0x7 << 4) #define STM32_TIM_CR2_MMS_RESET (0x0 << 4) #define STM32_TIM_CR2_MMS_ENABLE (0x1 << 4) #define STM32_TIM_CR2_MMS_UPDATE (0x2 << 4) #define STM32_TIM_CR2_MMS_PULSE (0x3 << 4) #define STM32_TIM_CR2_CCDS (0x1 << 3) /* ********************************************************************** *dma interrupt enable register ********************************************************************** */ #define PTR_STM32_TIM2_DIER (volatile unsigned int *)(PTR_STM32_TIM2_BASE + 0xc) #define PTR_STM32_TIM3_DIER (volatile unsigned int *)(PTR_STM32_TIM3_BASE + 0xc) #define PTR_STM32_TIM4_DIER (volatile unsigned int *)(PTR_STM32_TIM4_BASE + 0xc) #define PTR_STM32_TIM5_DIER (volatile unsigned int *)(PTR_STM32_TIM5_BASE + 0xc) #define STM32_TIM_DIER_UDE (1 << 8) #define STM32_TIM_DIER_CC4IE (1 << 4) #define STM32_TIM_DIER_CC3IE (1 << 3) #define STM32_TIM_DIER_CC2IE (1 << 2) #define STM32_TIM_DIER_CC1IE (1 << 1) #define STM32_TIM_DIER_UIE (1 << 0) /* ********************************************************************** *status register ********************************************************************** */ #define PTR_STM32_TIM2_SR (volatile unsigned int *)(PTR_STM32_TIM2_BASE + 0x10) #define PTR_STM32_TIM3_SR (volatile unsigned int *)(PTR_STM32_TIM3_BASE + 0x10) #define PTR_STM32_TIM4_SR (volatile unsigned int *)(PTR_STM32_TIM4_BASE + 0x10) #define PTR_STM32_TIM5_SR (volatile unsigned int *)(PTR_STM32_TIM5_BASE + 0x10) #define STM32_TIM_SR_CC4IF (1 << 4) #define STM32_TIM_SR_CC3IF (1 << 3) #define STM32_TIM_SR_CC2IF (1 << 2) #define STM32_TIM_SR_CC1IF (1 << 1) #define STM32_TIM_SR_UIF (1 << 0) /* ********************************************************************** *event generation register ********************************************************************** */ #define PTR_STM32_TIM2_EGR (volatile unsigned int *)(PTR_STM32_TIM2_BASE + 0x14) #define PTR_STM32_TIM3_EGR (volatile unsigned int *)(PTR_STM32_TIM3_BASE + 0x14) #define PTR_STM32_TIM4_EGR (volatile unsigned int *)(PTR_STM32_TIM4_BASE + 0x14) #define PTR_STM32_TIM5_EGR (volatile unsigned int *)(PTR_STM32_TIM5_BASE + 0x14) #define STM32_TIM_EGR_CC4G (1 << 4) #define STM32_TIM_EGR_CC3G (1 << 3) #define STM32_TIM_EGR_CC2G (1 << 2) #define STM32_TIM_EGR_CC1G (1 << 1) #define STM32_TIM_EGR_UG (1 << 0) /* ********************************************************************** *capture/compare enable register ********************************************************************** */ #define PTR_STM32_TIM2_CCER (volatile unsigned int *)(PTR_STM32_TIM2_BASE + 0x20) #define PTR_STM32_TIM3_CCER (volatile unsigned int *)(PTR_STM32_TIM3_BASE + 0x20) #define PTR_STM32_TIM4_CCER (volatile unsigned int *)(PTR_STM32_TIM4_BASE + 0x20) #define PTR_STM32_TIM5_CCER (volatile unsigned int *)(PTR_STM32_TIM5_BASE + 0x20) #define STM32_TIM_CCER_CC4E (1 << 12) #define STM32_TIM_CCER_CC3E (1 << 8) #define STM32_TIM_CCER_CC2E (1 << 4) #define STM32_TIM_CCER_CC1E (1 << 0) /* ********************************************************************** *counter register ********************************************************************** */ #define PTR_STM32_TIM2_CNT (volatile unsigned int *)(PTR_STM32_TIM2_BASE + 0x24) #define PTR_STM32_TIM3_CNT (volatile unsigned int *)(PTR_STM32_TIM3_BASE + 0x24) #define PTR_STM32_TIM4_CNT (volatile unsigned int *)(PTR_STM32_TIM4_BASE + 0x24) #define PTR_STM32_TIM5_CNT (volatile unsigned int *)(PTR_STM32_TIM5_BASE + 0x24) /* ********************************************************************** *prescaler register ********************************************************************** */ #define PTR_STM32_TIM2_PSC (volatile unsigned int *)(PTR_STM32_TIM2_BASE + 0x28) #define PTR_STM32_TIM3_PSC (volatile unsigned int *)(PTR_STM32_TIM3_BASE + 0x28) #define PTR_STM32_TIM4_PSC (volatile unsigned int *)(PTR_STM32_TIM4_BASE + 0x28) #define PTR_STM32_TIM5_PSC (volatile unsigned int *)(PTR_STM32_TIM5_BASE + 0x28) /* ********************************************************************** *auto reload register ********************************************************************** */ #define PTR_STM32_TIM2_ARR (volatile unsigned int *)(PTR_STM32_TIM2_BASE + 0x2c) #define PTR_STM32_TIM3_ARR (volatile unsigned int *)(PTR_STM32_TIM3_BASE + 0x2c) #define PTR_STM32_TIM4_ARR (volatile unsigned int *)(PTR_STM32_TIM4_BASE + 0x2c) #define PTR_STM32_TIM5_ARR (volatile unsigned int *)(PTR_STM32_TIM5_BASE + 0x2c) /* ********************************************************************** *capture/compare register 1 ********************************************************************** */ #define PTR_STM32_TIM2_CCR1 (volatile unsigned int *)(PTR_STM32_TIM2_BASE + 0x34) #define PTR_STM32_TIM3_CCR1 (volatile unsigned int *)(PTR_STM32_TIM3_BASE + 0x34) #define PTR_STM32_TIM4_CCR1 (volatile unsigned int *)(PTR_STM32_TIM4_BASE + 0x34) #define PTR_STM32_TIM5_CCR1 (volatile unsigned int *)(PTR_STM32_TIM5_BASE + 0x34) /* ********************************************************************** *capture/compare register 2 ********************************************************************** */ #define PTR_STM32_TIM2_CCR2 (volatile unsigned int *)(PTR_STM32_TIM2_BASE + 0x38) #define PTR_STM32_TIM3_CCR2 (volatile unsigned int *)(PTR_STM32_TIM3_BASE + 0x38) #define PTR_STM32_TIM4_CCR2 (volatile unsigned int *)(PTR_STM32_TIM4_BASE + 0x38) #define PTR_STM32_TIM5_CCR2 (volatile unsigned int *)(PTR_STM32_TIM5_BASE + 0x38) /* ********************************************************************** *capture/compare register 3 ********************************************************************** */ #define PTR_STM32_TIM2_CCR3 (volatile unsigned int *)(PTR_STM32_TIM2_BASE + 0x3c) #define PTR_STM32_TIM3_CCR3 (volatile unsigned int *)(PTR_STM32_TIM3_BASE + 0x3c) #define PTR_STM32_TIM4_CCR3 (volatile unsigned int *)(PTR_STM32_TIM4_BASE + 0x3c) #define PTR_STM32_TIM5_CCR3 (volatile unsigned int *)(PTR_STM32_TIM5_BASE + 0x3c) /* ********************************************************************** *capture/compare register 4 ********************************************************************** */ #define PTR_STM32_TIM2_CCR4 (volatile unsigned int *)(PTR_STM32_TIM2_BASE + 0x40) #define PTR_STM32_TIM3_CCR4 (volatile unsigned int *)(PTR_STM32_TIM3_BASE + 0x40) #define PTR_STM32_TIM4_CCR4 (volatile unsigned int *)(PTR_STM32_TIM4_BASE + 0x40) #define PTR_STM32_TIM5_CCR4 (volatile unsigned int *)(PTR_STM32_TIM5_BASE + 0x40) #endif
Saturday, August 24, 2013
bug in tclib_acquire_semaphore() and tclib_release_semaphore()
Turns out both functions were returning the value of the mutex instead of the compliment. strexb is a odd instruction code. It returns 0 when successful and 1 otherwise. But the function is setup to return 0 on error and 1 on success. In addition if a read (ldrexb) of the mutex returns it set to 1, I need to return 0 to the calling routine
/*
*****************************************************************
*description: acquire semaphore
*input: char *ptrWord = pointer to memory word
*output: 0 on error 1 on success
*void
*tclib_acquire_semaphore(unsigned char *ptrWord)
*****************************************************************
*/
.align 2
.global tclib_acquire_semaphore
/*
*****************************************************************
*r0 = ptrWord
*****************************************************************
*/
.thumb_func
tclib_acquire_semaphore:
push {r1-r2}
mov r1, #1
mov r2, r0
ldrexb r0, [r2] /*get value*/
cmp r0, #0
eorne r0, #1
bne tclib_get_mutex_exit
strexb r0, r1, [r2]
eor r0, #1
tclib_get_mutex_exit:
clrex
pop {r1-r2}
mov pc, lr
I also put the init routines inside stm32_init () and added a banner to to be printed to the terminal on power up. Now unto to USB firmware device development ...
/*
*****************************************************************
*description: acquire semaphore
*input: char *ptrWord = pointer to memory word
*output: 0 on error 1 on success
*void
*tclib_acquire_semaphore(unsigned char *ptrWord)
*****************************************************************
*/
.align 2
.global tclib_acquire_semaphore
/*
*****************************************************************
*r0 = ptrWord
*****************************************************************
*/
.thumb_func
tclib_acquire_semaphore:
push {r1-r2}
mov r1, #1
mov r2, r0
ldrexb r0, [r2] /*get value*/
cmp r0, #0
eorne r0, #1
bne tclib_get_mutex_exit
strexb r0, r1, [r2]
eor r0, #1
tclib_get_mutex_exit:
clrex
pop {r1-r2}
mov pc, lr
I also put the init routines inside stm32_init () and added a banner to to be printed to the terminal on power up. Now unto to USB firmware device development ...
bug in Vector Table Initialization
So after revisiting the program I realized that the errors were in a pattern that began with 0x2000 .... basically the address of RAM. It dawned on me that at the beginning the data in memory was fine ... so I single stepped to just after it got clobbered and that was in the stm32_nvic_init() function.
The problem was that I was initializing 256-2 vector table positions while only allocating space for 76. So I made the following changes
1) IE_stm32_ivt.S
2) IE_stm32.c
3) IE_stm32.ld
The problem was that I was initializing 256-2 vector table positions while only allocating space for 76. So I made the following changes
1) IE_stm32_ivt.S
.global stm32_ivt .global stm32_ivt_end .extern main .equ STM32_SRAM_BASE,0x20000000 .data stm32_ivt: .word STM32_SRAM_BASE + (20 * 1024) .word (main + 1) .skip (14 * 4) .skip (240 * 4) stm32_ivt_end: .text
2) IE_stm32.c
/* ********************************************************************** *install handlers for all vector positions *skip positions 0 = thread stack and 1 = reset address *dont hardcode size of table - determine it with stm32_ivt and _end ********************************************************************** */ ptrTemp = (volatile unsigned int *)STM32_NVIC_IVT_BASE; wdTemp = (&stm32_ivt_end - &stm32_ivt); for(wdCount=2; wdCount<wdTemp; wdCount++) { if(wdCount <= 6) ptrTemp[wdCount] = ((unsigned int)(stm32_nvic_fault_isr)\ | 0x1); else { if(wdCount == 15) ptrTemp[wdCount] = ((unsigned int)(stm32_nvic_systick_isr)\ | 0x1); else ptrTemp[wdCount] = ((unsigned int)(stm32_nvic_unknown_isr)\ | 0x1); } }
3) IE_stm32.ld
MEMORY { STM32_RAM : ORIGIN = 0x20000000, LENGTH = (20480 - 1024) } SECTIONS { .data : { *(.data); } > STM32_RAM .text : { *(.text); *(.rodata*); } > STM32_RAM .bss : { *(.bss); } > STM32_RAM }
Thursday, August 22, 2013
bug in compiler generated parameters passed to functions or just gdb' view of it?
Cant figure out why the compiler is passing invalid parameters to the tclib_printf() function. See gdb terminal interaction below. The asm dump looks fine to me
rombios@lenovo:~/PROJECTS/stm32$ arm-linux-gnueabi-gdb ./core_test.out
GNU gdb (GDB) 7.0.1-debian
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-linux-gnu --target=arm-linux-gnueabi".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
0x200003c8 in ?? ()
JTAG tap: stm32f1x.cpu tap/device found: 0x3ba00477 (mfg: 0x23b, part: 0xba00, ver: 0x3)
JTAG tap: stm32f1x.bs tap/device found: 0x16410041 (mfg: 0x020, part: 0x6410, ver: 0x1)
target state: halted
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x20000108 msp: 0x20005000
Reading symbols from /home/rombios/PROJECTS/stm32/core_test.out...done.
(gdb) l
25 /*
26 **********************************************************************
27 *initialization should start with:
28 *reset control clock registers
29 *general purpose input output registers
30 *universal asynchronous receiver transmitter registers
31 *nested vectored interrupt controller registers
32 **********************************************************************
33 */
34 stm32_rcc_cr_init();
(gdb)
35 stm32_gpio_init();
36 stm32_uart_init();
37 stm32_nvic_init();
38
39 wdTemp = strSystick.dwSeconds;
40 while(1)
41 {
42 while(wdTemp == strSystick.dwSeconds)
43 ;
44
(gdb)
45
46 wdTemp = wdTemp; /*dummy ins for breakpoint*/
47 tclib_printf("\r%d", wdTemp);
48 wdTemp = strSystick.dwSeconds;
49 }
50
51 return 0;
52 }
53
54
(gdb) b 46
Breakpoint 1 at 0x20000e0a: file apps/core/core_test.c, line 46.
(gdb) load
Loading section .text, size 0xe54 lma 0x20000000
Loading section .data, size 0x130 lma 0x20000e54
Start address 0x20000dd9, load size 3972
Transfer rate: 64 KB/sec, 1986 bytes/write.
(gdb) c
Continuing.
Breakpoint 1, main () at apps/core/core_test.c:46
46 wdTemp = wdTemp; /*dummy ins for breakpoint*/
(gdb) n
47 tclib_printf("\r%d", wdTemp);
(gdb) p wdTemp
$1 = 0
(gdb) s
tclib_printf (ptrString=0x0, wdValue=536874884) at tclib/IE_tclib.c:140
140 while ((*ptrString) != NULL)
(gdb) p strSystick
$2 = {dwMsTick = 0, dwSeconds = 1, dwMsTotal = 1000, ptrFunc = 0}
(gdb)
20000e0a: 687b ldr r3, [r7, #4]
20000e0c: 607b str r3, [r7, #4]
20000e0e: 687b ldr r3, [r7, #4]
20000e10: f640 6050 movw r0, #3664 ; 0xe50
20000e14: f2c2 0000 movt r0, #8192 ; 0x2000
20000e18: 4619 mov r1, r3
20000e1a: f7ff f9a3 bl 20000164 <tclib_printf>
20000164 <tclib_printf>:
20000164: b580 push {r7, lr}
20000166: b086 sub sp, #24
20000168: af00 add r7, sp, #0
2000016a: 6078 str r0, [r7, #4]
2000016c: 6039 str r1, [r7, #0]
rombios@lenovo:~/PROJECTS/stm32$ arm-linux-gnueabi-gdb ./core_test.out
GNU gdb (GDB) 7.0.1-debian
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-linux-gnu --target=arm-linux-gnueabi".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
0x200003c8 in ?? ()
JTAG tap: stm32f1x.cpu tap/device found: 0x3ba00477 (mfg: 0x23b, part: 0xba00, ver: 0x3)
JTAG tap: stm32f1x.bs tap/device found: 0x16410041 (mfg: 0x020, part: 0x6410, ver: 0x1)
target state: halted
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x20000108 msp: 0x20005000
Reading symbols from /home/rombios/PROJECTS/stm32/core_test.out...done.
(gdb) l
25 /*
26 **********************************************************************
27 *initialization should start with:
28 *reset control clock registers
29 *general purpose input output registers
30 *universal asynchronous receiver transmitter registers
31 *nested vectored interrupt controller registers
32 **********************************************************************
33 */
34 stm32_rcc_cr_init();
(gdb)
35 stm32_gpio_init();
36 stm32_uart_init();
37 stm32_nvic_init();
38
39 wdTemp = strSystick.dwSeconds;
40 while(1)
41 {
42 while(wdTemp == strSystick.dwSeconds)
43 ;
44
(gdb)
45
46 wdTemp = wdTemp; /*dummy ins for breakpoint*/
47 tclib_printf("\r%d", wdTemp);
48 wdTemp = strSystick.dwSeconds;
49 }
50
51 return 0;
52 }
53
54
(gdb) b 46
Breakpoint 1 at 0x20000e0a: file apps/core/core_test.c, line 46.
(gdb) load
Loading section .text, size 0xe54 lma 0x20000000
Loading section .data, size 0x130 lma 0x20000e54
Start address 0x20000dd9, load size 3972
Transfer rate: 64 KB/sec, 1986 bytes/write.
(gdb) c
Continuing.
Breakpoint 1, main () at apps/core/core_test.c:46
46 wdTemp = wdTemp; /*dummy ins for breakpoint*/
(gdb) n
47 tclib_printf("\r%d", wdTemp);
(gdb) p wdTemp
$1 = 0
(gdb) s
tclib_printf (ptrString=0x0, wdValue=536874884) at tclib/IE_tclib.c:140
140 while ((*ptrString) != NULL)
(gdb) p strSystick
$2 = {dwMsTick = 0, dwSeconds = 1, dwMsTotal = 1000, ptrFunc = 0}
(gdb)
20000e0a: 687b ldr r3, [r7, #4]
20000e0c: 607b str r3, [r7, #4]
20000e0e: 687b ldr r3, [r7, #4]
20000e10: f640 6050 movw r0, #3664 ; 0xe50
20000e14: f2c2 0000 movt r0, #8192 ; 0x2000
20000e18: 4619 mov r1, r3
20000e1a: f7ff f9a3 bl 20000164 <tclib_printf>
20000164 <tclib_printf>:
20000164: b580 push {r7, lr}
20000166: b086 sub sp, #24
20000168: af00 add r7, sp, #0
2000016a: 6078 str r0, [r7, #4]
2000016c: 6039 str r1, [r7, #0]
Makefile specified link order
Weird bug I encountered today and wasnt certain why changing the link order mattered but here is where the bug manifested itself and the latter correction:
The former results in a bug where global variables arent being updated. A breakpoint set in stm32_nvic_systick_isr and single stepping with prints of strSystick structure shows that, the structure elements arent being updated (incremented). However a dump of the asm code (arm-linux-gnueabi-objdump -d core_test.out) shows the correct instructions.
Changing the linke order to the latter corrects the problem. I cant understand this. strSystick is defined in IE_stm32.h and as such would be in core.o which is sourced to IE_stm32.c. Thats also where the handler stm32_nvic_systick_isr resides so this isnt making sense.
$(LD) -o $(APP)_test.out $(LDFLAGS) reset.o \ core.o \ tclibS.o \ tclibC.o \ $(APP)_test.o
$(LD) -o $(APP)_test.out $(LDFLAGS) reset.o \ tclibC.o \ tclibS.o \ core.o \ $(APP)_test.o
Weird bug I encountered today and wasnt certain why changing the link order
The former results in a bug where global variables arent being updated. A breakpoint set in stm32_nvic_systick_isr and single stepping with prints of strSystick structure shows that, the structure elements arent being updated (incremented). However a dump of the asm code (arm-linux-gnueabi-objdump -d core_test.out) shows the correct instructions.
Changing the linke order to the latter corrects the problem. I cant understand this. strSystick is defined in IE_stm32.h and as such would be in core.o which is sourced to IE_stm32.c. Thats also where the handler stm32_nvic_systick_isr resides so this isnt making sense.
IE_stm32.ld
/* *********************************************************************** *name: IE_stm32.ld *author: Samuel Igwe *date: 08/04/2013 *description: linker script that I have created for use in all stm32 * development related matters on this board * * it took some time to set this up. the ld manual was * sadly inadequate. I must credit zilogic's "embedded * programming with the gnu toolchain" at * www.bravegnu.org/gnu-eprog-dist.pdf * for clearing up issues related to loading the .data * section into its appropriate position in ram and * setting up the linker appropriately. * * first this is the memory map I had decided on * * 0x2000 4fff +++++++++++++++++++++++++++++++ * + ram + * 0x2000 0000 +++++++++++++++++++++++++++++++ * + + * 0x0001 ffff +++++++++++++++++++++++++++++++ * + flash + * 0x0000 0000 +++++++++++++++++++++++++++++++ * * * my stm32f103 board is jumpered to boot from flash at * offset 0x2000 0000. the first 256*4 will be reserved * for the NVIC interrupt vector table and hopefull the * last 512 bytes for the stack * * adding the variable _loadaddr_data_section_ to the end * of the .text along with the AT> directive places a copy * of the .data right after .text but leaves the virtual * addresses pointing at .data in ram * * in the assembler initialization file I can copy .data * from bottom of .text into .data in sram *********************************************************************** */ MEMORY { STM32_RAM : ORIGIN = 0x20000000, LENGTH = (20480 - 1024) } SECTIONS { .data : { *(.data); } > STM32_RAM .text : { *(.text); *(.rodata*); } > STM32_RAM .bss : { *(.bss); } > STM32_RAM }
Wednesday, August 14, 2013
"blx" and the .thumb_func gas directive
Encountered a major hard fault inside main(). Specifically the stm32_uart_init() functions call of tclib_memset().
under gdb, "layout asm" displayed the dis-assembly of the code and showed that instead of generating a "bl" instruction, the compiler was generating "blx" which implies a switch back to arm - which CANNOT happen on a cortex-m3
I had
-mthumb
-mno-thumb-interwork
-mcpu=cortex-m3
all set in CFLAGS.
Searching the net revealed the cause of it - a compiler "bug":
http://knowledgebase.nxp.com/showthread.php?t=674
tied to C functions calling assembly routines on a thumb ISA
The solution was to place the ".thumb_func" directive before any labels in the assembly source. This worked and got me passed this error ... but there are others ...
btw ".syntax unified" is needed to assemble my tclib.S asm source file with gcc
under gdb, "layout asm" displayed the dis-assembly of the code and showed that instead of generating a "bl" instruction, the compiler was generating "blx" which implies a switch back to arm - which CANNOT happen on a cortex-m3
I had
-mthumb
-mno-thumb-interwork
-mcpu=cortex-m3
all set in CFLAGS.
Searching the net revealed the cause of it - a compiler "bug":
http://knowledgebase.nxp.com/showthread.php?t=674
tied to C functions calling assembly routines on a thumb ISA
The solution was to place the ".thumb_func" directive before any labels in the assembly source. This worked and got me passed this error ... but there are others ...
btw ".syntax unified" is needed to assemble my tclib.S asm source file with gcc
core_test.c
/* ********************************************************************** *name: core_test.c *author: Samuel Igwe *date: 08/12/2013 *description: Igbo Embedded core_test.c source. goal is to test out * initialization * uart * systick timer * interrupts * tclib library * all in preparation for usb "device" development ********************************************************************** */ #include "IE_tclib.h" #include "IE_stm32.h" int main() { volatile unsigned int wdTemp; stm32_init(); wdTemp = stm32_get_seconds(); while(1) { while(wdTemp == stm32_get_seconds()) ; tclib_printf("\r%d", wdTemp); wdTemp = stm32_get_seconds(); } return 0; }
Monday, August 12, 2013
IE_stm32_usb.c
/* ********************************************************************** *name: IE_stm32_usb.c *author: Samuel Igwe *date: 08/24/2013 *description: Igbo Embedded stm32.c usb source ********************************************************************** */ #include "IE_stm32.h" #include "IE_tclib.h" /* ********************************************************************** *#define functions for USB enumeration ********************************************************************** */ void stm32_usb_isr_control_in(void); void stm32_usb_isr_control_out(void); void stm32_usb_isr_user_in(unsigned int wdEndP); void stm32_usb_isr_user_out(unsigned int wdEndP); void stm32_usb_cancel_queued_IN_transfers(unsigned int wdEndP); void stm32_usb_dequeue_IN_transfers(unsigned int wdEndP); void stm32_usb_queue_IN_transfers(unsigned int wdEndP,\ unsigned char *ptrBuffer,\ unsigned int wdSize); void stm32_usb_set_epr_stat(unsigned int wdEndP,\ unsigned int wdNewStat,\ unsigned int wdOffset); void stm32_usb_clear_epr_ctr(unsigned int wdEndP,\ unsigned int wdMask); void stm32_usb_enable_endp(unsigned int wdEndP,\ unsigned int wdEndPType); void stm32_usb_set_epr_dtog(unsigned int wdEndP,\ int wdNewStat,\ unsigned int wdOffset); /* ********************************************************************** *#define constants for USB enumeration ********************************************************************** */ static volatile unsigned int wdUsbState, wdUsbAddr, wdUsbArgs; struct STR_USB_PKT_XFER{ unsigned char *ptrCtrlBuf; int wdCtrlSize; unsigned char *ptrUserBuf; int wdUserSize; }strUsbPktXfer; #define STMUSB_DEVICE_CONFIGURED (1 << 0) #define STMUSB_DEVICE_IDLE 0x0ff #define USB_NVIC_IRQ_NUM 20 /* ********************************************************************** *description: routine to properly set the EP_TYPE bits in the * Endpoint register. *input: unsigned int wdEndP = endpoint number * unsigned int wdEndPType = the following * STM32_USB_EPR_EP_TYPE_BULK * STM32_USB_EPR_EP_TYPE_CONTROL * STM32_USB_EPR_EP_TYPE_ISO * STM32_USB_EPR_EP_TYPE_INTERRUPT *output: void * *note: the CTR_RX and CTR_TX bits are governed by the rules * 1 = dont change 0 = clear ********************************************************************** */ void stm32_usb_enable_endp(unsigned int wdEndP,\ unsigned int wdEndPType) { unsigned int wdTemp; /*retrieve the current register value*/ wdTemp = *(PTR_STM32_USB_EP0R + wdEndP); /*invariants - values that will not modify these reg bits*/ wdTemp &= ~(STM32_USB_EPR_STAT_TX_MASK | \ STM32_USB_EPR_STAT_RX_MASK | \ (STM32_USB_EPR_DTOG_TX | STM32_USB_EPR_DTOG_RX)); wdTemp |= (STM32_USB_EPR_CTR_TX | STM32_USB_EPR_CTR_RX); /*set EndPType and number*/ wdTemp |= (wdEndPType << STM32_USB_EPR_EP_TYPE_OFFSET); wdTemp |= wdEndP; /*set the current register value*/ *(PTR_STM32_USB_EP0R + wdEndP) = (wdTemp | wdEndP); } /* ********************************************************************** *description: routine to properly set the RX and TX STAT bits in the * Endpoint register. *input: unsigned int wdEndP = endpoint number * unsigned int wdMask = the following * STM32_USB_EPR_CTR_RX * STM32_USB_EPR_CTR_TX *output: void * *note: the CTR_RX and CTR_TX bits are governed by the rules * 1 = dont change 0 = clear ********************************************************************** */ void stm32_usb_clear_epr_ctr(unsigned int wdEndP,\ unsigned int wdMask) { unsigned int wdTemp; /*retrieve the current register value*/ wdTemp = *(PTR_STM32_USB_EP0R + wdEndP); /*invariants - values that will not modify these reg bits*/ wdTemp &= ~(STM32_USB_EPR_STAT_TX_MASK | \ STM32_USB_EPR_STAT_RX_MASK | \ (STM32_USB_EPR_DTOG_TX | STM32_USB_EPR_DTOG_RX)); wdTemp |= (STM32_USB_EPR_CTR_TX | STM32_USB_EPR_CTR_RX); wdTemp &= ~wdMask; /*set the current register value*/ *(PTR_STM32_USB_EP0R + wdEndP) = (wdTemp | wdEndP); } /* ********************************************************************** *description: routine to properly set or toggle the DTOG_RX | DTOG_TX * bits of the Endpoint register. *input: unsigned int wdEndP = endpoint number * unsigned int wdNewStat = the following * 0 = set to 0 * 1 = set to 1 * -1 = toggle * unsigned int wdOffset = DTOG_RX or DTOG_TX STAT * STM32_USB_EPR_DTOG_RX_OFFSET * STM32_USB_EPR_DTOG_TX_OFFSET *output: void * *note: the DTOG_RX and DTOG_TX bits are governed by the rules * 0 = dont change 1 = TOGGLE ********************************************************************** */ void stm32_usb_set_epr_dtog(unsigned int wdEndP,\ int wdNewStat,\ unsigned int wdOffset) { unsigned int wdMask, wdTemp; /*retrieve the current register value*/ wdMask = *(PTR_STM32_USB_EP0R + wdEndP); wdTemp = wdMask; /*wdMask has STAT position extracted*/ if(wdOffset == STM32_USB_EPR_DTOG_RX_OFFSET) wdMask &= STM32_USB_EPR_DTOG_RX; else wdMask &= STM32_USB_EPR_DTOG_TX; /*normalize then compute XOR of value and mask*/ wdMask >>= wdOffset; if(wdNewStat != -1 && wdMask == wdNewStat) return; if(wdNewStat == -1) wdNewStat = 1; wdMask ^= wdNewStat; wdMask <<= wdOffset; /*mask out non important bits*/ if(wdOffset == STM32_USB_EPR_DTOG_RX_OFFSET) wdMask &= STM32_USB_EPR_DTOG_RX; else wdMask &= STM32_USB_EPR_DTOG_TX; /*invariants - values that will not modify these reg bits*/ wdTemp &= ~(STM32_USB_EPR_STAT_TX_MASK | \ STM32_USB_EPR_STAT_RX_MASK | \ (STM32_USB_EPR_DTOG_TX | STM32_USB_EPR_DTOG_RX)); wdTemp |= (STM32_USB_EPR_CTR_TX | STM32_USB_EPR_CTR_RX); /*set user settings*/ wdTemp |= wdMask; /*update register*/ *(PTR_STM32_USB_EP0R + wdEndP) = (wdTemp | wdEndP); } /* ********************************************************************** *description: routine to properly set the RX and TX STAT bits in the * Endpoint register. *input: unsigned int wdEndP = endpoint number * unsigned int wdNewStat = the following * STM32_USB_EPR_STAT_RX_DISABLE * STM32_USB_EPR_STAT_TX_DISABLE * * STM32_USB_EPR_STAT_RX_STALL * STM32_USB_EPR_STAT_TX_STALL * * STM32_USB_EPR_STAT_RX_NAK * STM32_USB_EPR_STAT_TX_NAK * * STM32_USB_EPR_STAT_RX_VALID * STM32_USB_EPR_STAT_TX_VALID * unsigned int wdOffset = RX or TX STAT * STM32_USB_EPR_STAT_RX_OFFSET * STM32_USB_EPR_STAT_TX_OFFSET *output: void * *note: the RX_STAT and TX_STAT bits are governed by the rules * 0 = dont change 1 = TOGGLE * A major error was not taking this into consideration ********************************************************************** */ void stm32_usb_set_epr_stat(unsigned int wdEndP,\ unsigned int wdNewStat,\ unsigned int wdOffset) { unsigned int wdMask, wdTemp; /*retrieve the current register value*/ wdMask = *(PTR_STM32_USB_EP0R + wdEndP); wdTemp = wdMask; /*wdMask has STAT position extracted*/ if(wdOffset == STM32_USB_EPR_STAT_RX_OFFSET) wdMask &= STM32_USB_EPR_STAT_RX_MASK; else wdMask &= STM32_USB_EPR_STAT_TX_MASK; /*normalize then compute XOR of value and mask*/ wdMask >>= wdOffset; wdMask ^= wdNewStat; wdMask <<= wdOffset; /*mask out non important bits*/ if(wdOffset == STM32_USB_EPR_STAT_RX_OFFSET) wdMask &= STM32_USB_EPR_STAT_RX_MASK; else wdMask &= STM32_USB_EPR_STAT_TX_MASK; /*invariants - values that will not modify these reg bits*/ wdTemp &= ~(STM32_USB_EPR_STAT_TX_MASK | \ STM32_USB_EPR_STAT_RX_MASK | \ (STM32_USB_EPR_DTOG_TX | STM32_USB_EPR_DTOG_RX)); wdTemp |= (STM32_USB_EPR_CTR_TX | STM32_USB_EPR_CTR_RX); /*set user settings*/ wdTemp |= wdMask; /*update register*/ *(PTR_STM32_USB_EP0R + wdEndP) = (wdTemp | wdEndP); } /* ********************************************************************** *description: tx transfer cancel routine *input: unsigned int wdEndP = endpoint number *note: called at post_reset and whenever the need arises ********************************************************************** */ void stm32_usb_cancel_queued_IN_transfers(unsigned int wdEndP) { if(wdEndP == STMUSB_ENDP_USER_NUM) strUsbPktXfer.wdUserSize = -1; else strUsbPktXfer.wdCtrlSize = -1; } /* ********************************************************************** *description: tx transfer dequeue routine *input: unsigned int wdEndP = endpoint number *note: be prepared to deal with zero length packets ********************************************************************** */ void stm32_usb_dequeue_IN_transfers(unsigned int wdEndP) { unsigned char *ptrBuf, **ptrPtrBuf; int *ptrCount, wdCount, wdEndPSize; if(wdEndP == STMUSB_ENDP_USER_NUM) { ptrBuf = strUsbPktXfer.ptrUserBuf; ptrPtrBuf = (unsigned char **)&strUsbPktXfer.ptrUserBuf; ptrCount = &strUsbPktXfer.wdUserSize; wdCount = *ptrCount; wdEndPSize= STMUSB_ENDP_USER_SIZE; } else { ptrBuf = (unsigned char *)strUsbPktXfer.ptrCtrlBuf; ptrPtrBuf = (unsigned char **)&strUsbPktXfer.ptrCtrlBuf; ptrCount = &strUsbPktXfer.wdCtrlSize; wdCount = *ptrCount; wdEndPSize= STMUSB_ENDP_CTRL_SIZE; } /*check if xfer is >= 0, return if its -1*/ if(wdCount < 0) /*check xfer == -1 or xfer >=0 */ return; else { if(wdCount == 0) /*should we generate a zero length packet*/ { *ptrCount = -1; /*end future xfers*/ stm32_usb_endp_send_packet(wdEndP,\ ptrBuf,\ wdEndPSize,\ 0); } else { if(wdCount >= wdEndPSize) wdCount = wdEndPSize; stm32_usb_endp_send_packet(wdEndP,\ ptrBuf,\ wdEndPSize,\ wdCount); /*update variables*/ *(ptrPtrBuf) = (unsigned char *)(ptrBuf + wdCount); *(ptrCount) -= wdCount; /* ******************************************************* *prep for a zlp on the next interrupt if *this is the last transfer (wdCount == 0) and *the transfer size matches the endpoint buffer size ******************************************************* */ if(wdCount == wdEndPSize && (*ptrCount) == 0) ; /*do nothing here zlp on next int*/ else { if((*ptrCount) == 0) (*ptrCount) = -1; else ; /*do nothing transfer continues*/ } } } } /* ********************************************************************** *description: tx transfer queue routine *input: unsigned int wdEndP = endpoint number * unsigned char *ptrBuffer = pointer to buffer * unsigned int wdSize = buffer size in bytes *notes: store pointers to the global record. stores count of * records ********************************************************************** */ void stm32_usb_queue_IN_transfers(unsigned int wdEndP,\ unsigned char *ptrBuffer,\ unsigned int wdSize) { if(wdEndP == STMUSB_ENDP_USER_NUM) { strUsbPktXfer.ptrUserBuf = ptrBuffer; strUsbPktXfer.wdUserSize = wdSize; } else { strUsbPktXfer.ptrCtrlBuf = ptrBuffer; strUsbPktXfer.wdCtrlSize = wdSize; } } /* ********************************************************************** *description: setup particular portA pin to an input, so its no * longer driving the pin *input: unsigned int wdPin = PAx pin number to use. it must be * portA block pins ONLY *note: this should be called inside the usb isr on RESET flag *implemented: using three position jumper pin with all three wire * wrapped linked - and a jumper from PAx to one of the * positions ********************************************************************** */ void stm32_usb_connect_pullup(unsigned int wdPin) { volatile unsigned int wdTemp, wdMask; wdTemp = (*PTR_STM32_GPIO_A_CRL); wdTemp &= ~(0x0f << (wdPin << 2)); wdMask = ((STM32_GPIO_CNF_IN_FLOATING << 2) | \ STM32_GPIO_MODE_INPUT_MODE) << (wdPin << 2); (*PTR_STM32_GPIO_A_CRL) = (wdMask | wdTemp); } /* ********************************************************************** *description: I am using PAX (external wire to Dplus pin on J6 facing * the USB connector) to pull up the line to trigger the * USB HOST enumeration. * setup PAX to generic output. pull it high *input: unsigned int wdPin = PAx pin number to use. it must be * portA block pins ONLY ********************************************************************** */ void stm32_usb_disconnect_pullup(unsigned int wdPin) { volatile unsigned int wdTemp, wdMask; (*PTR_STM32_GPIO_A_BSRR) = ((1 << wdPin) << 16); wdTemp = (*PTR_STM32_GPIO_A_CRL); wdTemp &= ~(0x0f << (wdPin << 2)); wdMask = ((STM32_GPIO_CNF_OUT_GEN_PUSH_PULL << 2) | \ STM32_GPIO_MODE_OUTPUT_2MHZ) << (wdPin << 2); (*PTR_STM32_GPIO_A_CRL) = (wdMask | wdTemp); } /* ********************************************************************** *description: usb user out isr handler *input: unsigned int wdEndP * *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 = ********************************************************************** */ void stm32_usb_isr_user_out(unsigned int wdEndP) { unsigned char sbBuffer[STMUSB_ENDP_CTRL_MAX_SIZE + 1]; unsigned int wdTemp, wdSize, *ptrEndP, *ptrAddr; unsigned char *ptrTemp; /* ********************************************************************** *handle usb endpoints. clear endpoint interrupts *first grab a snapshot of the interrupt status register ********************************************************************** */ ptrEndP = (unsigned int *)PTR_STM32_USB_EP0R; ptrEndP += wdEndP; wdTemp = (*ptrEndP); if(((wdTemp & STM32_USB_EPR_CTR_RX) != STM32_USB_EPR_CTR_RX) ||\ ((wdTemp & STM32_USB_EPR_EA_MASK)!= wdEndP)) return; else { /* ************************************************************** *receive data if available ************************************************************** */ wdSize = stm32_usb_endp_get_packet(wdEndP,\ sbBuffer,\ STMUSB_ENDP_USER_SIZE); stm32_usb_clear_epr_ctr(wdEndP, STM32_USB_EPR_CTR_RX); } #ifdef DEBUG wdTemp = (STMUSB_ENDP_CTRL_MAX_SIZE - wdSize); ptrTemp = (unsigned char *)(sbBuffer + wdSize); if(((wdSize << 1) + wdSize) < wdTemp) { unsigned int wdCount; for(wdCount=0; wdCount<wdSize; wdCount++) { wdTemp = sbBuffer[wdCount]; tclib_itoa(wdTemp,(unsigned char *) ptrTemp); ptrTemp += 2; (*ptrTemp) =' '; ptrTemp += 1; } *(ptrTemp - 1) = 0; tclib_printf("%s\n", (unsigned int)(sbBuffer + wdSize)); } #endif /* ********************************************************************** *process packet ********************************************************************** */ tclib_memcpy((unsigned char *)&wdTemp, sbBuffer+4, sizeof(int)); ptrAddr = (unsigned char *)wdTemp; if(sbBuffer[2] != 0xed || sbBuffer[3] != 0xfe) { tclib_printf("packet signature missing\n", 0); return; } if(sbBuffer[0] == 0) /*IN*/ { wdTemp = *ptrAddr; /*retrieve value*/ wdTemp = \ stm32_usb_endp_send_packet(wdEndP,\ (unsigned char *)&wdTemp,\ STMUSB_ENDP_USER_SIZE,\ sizeof(int)); if(wdTemp != sizeof(int)) { tclib_printf("isr_user_out: send_packet_error\n", 0); return; } stm32_usb_cancel_queued_IN_transfers(wdEndP); #ifdef IGNORE /*wait until transfer is complete before continuing*/ do { wdTemp = *(PTR_STM32_USB_EP0R + wdEndP); wdTemp &= STM32_USB_EPR_CTR_TX; }while(wdTemp != STM32_USB_EPR_CTR_TX); #endif /*clear TX interrupt*/ stm32_usb_clear_epr_ctr(wdEndP, STM32_USB_EPR_CTR_TX); } else { if(sbBuffer[0] != 1) /*OUT*/ return; wdTemp = sbBuffer[1]; wdTemp -= 8; /*subtract command packet*/ wdSize -= 8; /*ditto*/ if(wdSize != wdTemp) /*i need to get the data*/ { /*wait until data is available before continuing*/ do { wdTemp = *(PTR_STM32_USB_EP0R + wdEndP); wdTemp &= STM32_USB_EPR_CTR_RX; }while(wdTemp != STM32_USB_EPR_CTR_RX); wdSize = stm32_usb_endp_get_packet(wdEndP, \ sbBuffer,\ STMUSB_ENDP_USER_SIZE); /*clear RX interrupt*/ stm32_usb_clear_epr_ctr(wdEndP, STM32_USB_EPR_CTR_RX); if(wdSize >= sizeof(int)) tclib_memcpy((unsigned char *)&wdTemp, sbBuffer, sizeof(int)); else return; } else tclib_memcpy((unsigned char *)&wdTemp, sbBuffer+8, sizeof(int)); /*set value*/ *ptrAddr = wdTemp; } } /* ********************************************************************** *description: usb user in isr handler *input: unsigned int wdEndP ********************************************************************** */ void stm32_usb_isr_user_in(unsigned int wdEndP) { volatile unsigned int *ptrTemp, wdTemp; /* ********************************************************************** *handle usb endpoints. clear endpoint interrupts *first grab a snapshot of the interrupt status register ********************************************************************** */ ptrTemp = PTR_STM32_USB_EP0R; ptrTemp += wdEndP; wdTemp = (*ptrTemp); if(((wdTemp & STM32_USB_EPR_CTR_TX) != STM32_USB_EPR_CTR_TX) ||\ ((wdTemp & STM32_USB_EPR_EA_MASK)!= wdEndP)) return; else { /* ************************************************************** *transmit data if available ************************************************************** */ stm32_usb_dequeue_IN_transfers(wdEndP); stm32_usb_clear_epr_ctr(wdEndP, STM32_USB_EPR_CTR_TX); } } /* ********************************************************************** *description: usb control in isr handler ********************************************************************** */ void stm32_usb_isr_control_in(void) { volatile unsigned int wdTemp; /* ********************************************************************** *handle usb endpoints. clear endpoint interrupts *first grab a snapshot of the interrupt status register ********************************************************************** */ wdTemp = (*PTR_STM32_USB_EP0R); if((wdTemp & STM32_USB_EPR_CTR_TX) != STM32_USB_EPR_CTR_TX) return; else { /* ************************************************************** *transmit data if available *data toggle is set by caller to stm32_queue_IN_transfers to 1 *subsequent toggles are done by the hardware ************************************************************** */ stm32_usb_dequeue_IN_transfers(0); stm32_usb_clear_epr_ctr(0, STM32_USB_EPR_CTR_TX); } } /* ********************************************************************** *description: usb control out isr handler *output: none ********************************************************************** */ void stm32_usb_isr_control_out(void) { unsigned char sbBuffer[STMUSB_ENDP_CTRL_MAX_SIZE + 1]; unsigned char *ptrTemp; volatile unsigned int wdTemp, wdSize, wdIndex, wdType; /* ********************************************************************** *handle usb endpoints. clear endpoint interrupts *first grab a snapshot of the interrupt status register ********************************************************************** */ wdTemp = (*PTR_STM32_USB_EP0R); #ifdef IGNORE if(((wdTemp & STM32_USB_EPR_CTR_RX) != STM32_USB_EPR_CTR_RX) ||\ ((wdTemp & STM32_USB_EPR_SETUP) != STM32_USB_EPR_SETUP)) #endif if((wdTemp & STM32_USB_EPR_CTR_RX) != STM32_USB_EPR_CTR_RX) return; else { /* ************************************************************** *receive data if available ************************************************************** */ wdSize = stm32_usb_endp_get_packet(0, \ sbBuffer,\ STMUSB_ENDP_CTRL_MAX_SIZE); stm32_usb_clear_epr_ctr(0, STM32_USB_EPR_CTR_RX); } #ifdef DEBUG if(wdSize >= 8) { wdTemp = (STMUSB_ENDP_CTRL_MAX_SIZE - wdSize); ptrTemp = (unsigned char *)(sbBuffer + wdSize); if(((wdSize << 1) + wdSize) < wdTemp) { unsigned int wdCount; for(wdCount=0; wdCount<wdSize; wdCount++) { wdTemp = sbBuffer[wdCount]; tclib_itoa(wdTemp, (unsigned char *)ptrTemp); ptrTemp += 2; (*ptrTemp) =' '; ptrTemp += 1; } *(ptrTemp - 1) = 0; tclib_printf("%s\n", (unsigned int)(sbBuffer + wdSize)); } } #endif /* ********************************************************************** *evaluate SETUP command packet ********************************************************************** */ wdTemp = sbBuffer[USBDEV_SETUP_REQTYPE_OFFSET]; if((wdTemp & USBDEV_SETUP_REQTYPE_DIR_MASK) == USBDEV_SETUP_REQTYPE_DIR_H_TO_D) { /*these are SET commands*/ switch(sbBuffer[USBDEV_SETUP_REQUEST_OFFSET]) { case USBDEV_REQ_SET_ADDRESS: { /*return ZLP = zero length packet, before enabling dev*/ stm32_usb_set_epr_dtog(0,\ 1,\ STM32_USB_EPR_DTOG_TX_OFFSET); wdTemp = \ stm32_usb_endp_send_packet(0,\ (unsigned char *)&wdTemp,\ STMUSB_ENDP_CTRL_SIZE,\ 0); if(wdTemp != 0) { tclib_printf("isr_control_out: send_packet_error\n", 0); return; } /*wait until transfer is complete before setting address*/ do { wdTemp = *(PTR_STM32_USB_EP0R + 0); wdTemp &= STM32_USB_EPR_CTR_TX; }while(wdTemp != STM32_USB_EPR_CTR_TX); /*clear TX interrupt*/ stm32_usb_clear_epr_ctr(0, STM32_USB_EPR_CTR_TX); /*alert user and set the bus address*/ wdTemp = sbBuffer[USBDEV_SETUP_VALUE_OFFSET]; (*PTR_STM32_USB_DADDR) = ((STM32_USB_DADDR_EF) | wdTemp); tclib_printf("usb device address = %x\n", wdTemp); break; } case USBDEV_REQ_SET_CONFIGURATION: { /*return ZLP = zero length packet*/ stm32_usb_set_epr_dtog(0,\ 1,\ STM32_USB_EPR_DTOG_TX_OFFSET); wdTemp = \ stm32_usb_endp_send_packet(0,\ (unsigned char *)&wdTemp,\ STMUSB_ENDP_CTRL_SIZE,\ 0); if(wdTemp != 0) { tclib_printf("isr_control_out: send_packet_error\n", 0); return; } break; } case USBDEV_REQ_SET_FEATURE: /*not supported*/ case USBDEV_REQ_SET_INTERFACE: /*not supported*/ case USBDEV_REQ_CLEAR_FEATURE: /*not supported*/ case USBDEV_REQ_SET_DESCRIPTOR: /*not supported*/ default: { break; } } } else { /*these are GET* commands*/ switch(sbBuffer[USBDEV_SETUP_REQUEST_OFFSET]) { case USBDEV_REQ_GET_DESCRIPTOR: { wdType = (sbBuffer[(USBDEV_SETUP_VALUE_OFFSET + 1)] & 0x0ff); wdIndex = (sbBuffer[USBDEV_SETUP_VALUE_OFFSET] & 0x0ff); wdSize = (sbBuffer[USBDEV_SETUP_LENGTH_OFFSET] & 0x0ff); /* ********************************************* determine descriptor type ********************************************* */ switch(wdType) { case USBDEV_DESCR_TYPE_DEVICE: { ptrTemp = (unsigned char *)sbDevDescr; break; } case USBDEV_DESCR_TYPE_CONFIGURATION: { ptrTemp = (unsigned char *)sbConfDescr; break; } case USBDEV_DESCR_TYPE_STRING: { wdTemp = swUsbDevDescr[wdIndex]; ptrTemp = (unsigned char *)wdTemp; break; } default: { tclib_printf("unsupported descriptor type = %x\n", wdType); break; } } stm32_usb_set_epr_dtog(0,\ 1,\ STM32_USB_EPR_DTOG_TX_OFFSET); stm32_usb_queue_IN_transfers(0,\ (unsigned char *)ptrTemp,\ wdSize); stm32_usb_dequeue_IN_transfers(0); break; } case USBDEV_REQ_GET_STATUS: { wdTemp = 0; stm32_usb_set_epr_dtog(0,\ 1,\ STM32_USB_EPR_DTOG_TX_OFFSET); wdTemp = \ stm32_usb_endp_send_packet(0,\ (unsigned char *)&wdTemp,\ STMUSB_ENDP_CTRL_SIZE,\ 2); if(wdTemp != 2) { tclib_printf("isr_control_out: send_packet_error\n", 0); return; } break; } case USBDEV_REQ_GET_CONFIGURATION: { wdTemp = 0; stm32_usb_set_epr_dtog(0,\ 1,\ STM32_USB_EPR_DTOG_TX_OFFSET); wdTemp = \ stm32_usb_endp_send_packet(0,\ (unsigned char *)&wdTemp,\ STMUSB_ENDP_CTRL_SIZE,\ 1); if(wdTemp != 1) { tclib_printf("isr_control_out: send_packet_error\n", 0); return; } break; } case USBDEV_REQ_SYNTH_FRAME: /*doesnt apply*/ case USBDEV_REQ_GET_INTERFACE: /*doesnt apply*/ default: { break; } } } } /* ********************************************************************** *description: first stage usb isr handler ********************************************************************** */ void stm32_usb_isr(void) { volatile unsigned int wdIrqStat, wdEndP; /* ********************************************************************** *is this a RESET interrupt? *handle it. re-initialize the usb endpoint sub-system ********************************************************************** */ wdIrqStat = (*PTR_STM32_USB_ISTR); if((wdIrqStat & STM32_USB_ISTR_RESET) == STM32_USB_ISTR_RESET) { wdUsbState = STM32_USB_ISTR_RESET; (*PTR_STM32_USB_ISTR) = ~wdUsbState; /*disable interrupts */ asm("cpsid i"); #ifdef DEBUG (*PTR_STM32_TIM3_CNT) =0; #endif stm32_usb_post_reset_setup(STMUSB_ENDP_USER_NUM,\ STM32_USB_EPR_EP_TYPE_BULK, STMUSB_ENDP_USER_SIZE); #ifdef DEBUG wdUsbState = (*PTR_STM32_TIM3_CNT); #endif /*enable interrupts anew*/ asm("cpsie i"); #ifdef DEBUG tclib_printf("--------RESET----------- %duS\n", wdUsbState); #else tclib_printf("--------RESET----------- \n", 0); #endif wdUsbState = 0; } /* ********************************************************************** *is this a CORRECT TRANSFER interrupt? *handle it. process the data ********************************************************************** */ wdIrqStat = (*PTR_STM32_USB_ISTR); if((wdIrqStat & STM32_USB_ISTR_CTR) == STM32_USB_ISTR_CTR) { wdEndP = (wdIrqStat & STM32_USB_ISTR_EP_ID_MASK); wdEndP >>= STM32_USB_ISTR_EP_ID_OFFSET; /* ************************************************************** *control endpoint can go in either direction = IN or OUT * its complexity requires a function that handles a * a state machine *user endpoint can go in either direction = IN or OUT * this is simple data exchange nothing more ************************************************************** */ switch((wdIrqStat & STM32_USB_ISTR_DIR_MASK)) { case STM32_USB_ISTR_DIR_IN: { if(wdEndP == 0) stm32_usb_isr_control_in(); else stm32_usb_isr_user_in(wdEndP); break; } case STM32_USB_ISTR_DIR_OUT: { stm32_usb_cancel_queued_IN_transfers(0); if(wdEndP == 0) stm32_usb_isr_control_out(); else stm32_usb_isr_user_out(wdEndP); break; } } } } /* ********************************************************************** *description: usb initialization function *note: setup the usb function then setup the endpoint for * control (0) and user endpoint (interrupt for now) ********************************************************************** */ void stm32_usb_init(void) { volatile unsigned int wdTemp; /* ********************************************************************** *clear out record ********************************************************************** */ tclib_memset((unsigned char *)&strUsbPktXfer, -1, sizeof(strUsbPktXfer)); /* ********************************************************************** *now setup the usb interface ********************************************************************** */ wdTemp = STM32_USB_CNTR_CTRM; wdTemp |= STM32_USB_CNTR_RESETM; //wdTemp |= STM32_USB_CNTR_SUSPM; #ifdef ISOCHRONOUS wdTemp |= STM32_USB_CNTR_SOFM; #endif (*PTR_STM32_USB_CNTR) = wdTemp; stm32_usb_pre_reset_setup(STMUSB_ENDP_USER_NUM,\ STM32_USB_EPR_EP_TYPE_BULK, STMUSB_ENDP_USER_SIZE); wdTemp = ~(STM32_USB_ISTR_RESET | STM32_USB_ISTR_SUSP); (*PTR_STM32_USB_ISTR) = wdTemp; stm32_nvic_install_isr(USB_NVIC_IRQ_NUM, (unsigned int)stm32_usb_isr); } /* ********************************************************************** *description: usb routine to be executed after host bus initiated * reset *inputs: unsigned int wdUserEndPNum = user endpoint number * unsigned int wdUserEndPType= endpoint type * STM32_USB_EPR_EP_TYPE_BULK * STM32_USB_EPR_EP_TYPE_CONTROL * STM32_USB_EPR_EP_TYPE_ISO * STM32_USB_EPR_EP_TYPE_INTERRUPT * unsigned int wdUserEndPSize= 8,16,32,64 etc *note: crucial to call stm32_usb_clear_epr_cnt to clear rx and * tx SPURIOUS interrupts!!! ********************************************************************** */ void stm32_usb_post_reset_setup(unsigned int wdUserEndPNum,\ unsigned int wdUserEndPType,\ unsigned int wdUserEndPSize) { stm32_usb_set_epr_dtog(0,\ 0,\ STM32_USB_EPR_DTOG_RX_OFFSET); stm32_usb_set_epr_dtog(0,\ 1,\ STM32_USB_EPR_DTOG_TX_OFFSET); stm32_usb_set_epr_stat(0,\ STM32_USB_EPR_STAT_RX_VALID,\ STM32_USB_EPR_STAT_RX_OFFSET); stm32_usb_set_epr_stat(0,\ STM32_USB_EPR_STAT_TX_NAK,\ STM32_USB_EPR_STAT_TX_OFFSET); stm32_usb_cancel_queued_IN_transfers(0); stm32_usb_clear_epr_ctr(0, STM32_USB_EPR_CTR_RX); stm32_usb_clear_epr_ctr(0, STM32_USB_EPR_CTR_TX); stm32_usb_enable_endp(0, STM32_USB_EPR_EP_TYPE_CONTROL); stm32_usb_set_epr_stat(wdUserEndPNum,\ STM32_USB_EPR_STAT_RX_VALID,\ STM32_USB_EPR_STAT_RX_OFFSET); stm32_usb_set_epr_stat(wdUserEndPNum,\ STM32_USB_EPR_STAT_TX_NAK,\ STM32_USB_EPR_STAT_TX_OFFSET); stm32_usb_cancel_queued_IN_transfers(wdUserEndPNum); stm32_usb_clear_epr_ctr(wdUserEndPNum, STM32_USB_EPR_CTR_RX); stm32_usb_clear_epr_ctr(wdUserEndPNum, STM32_USB_EPR_CTR_TX); stm32_usb_enable_endp(wdUserEndPNum, wdUserEndPType); /*set and enable device addr*/ (*PTR_STM32_USB_DADDR) = ((STM32_USB_DADDR_EF) | 0); } /* ********************************************************************** *description: usb routine to be executed before host bus initiated * reset *inputs: unsigned int wdUserEndPNum = user endpoint number * unsigned int wdUserEndPType= endpoint type * STM32_USB_EPR_EP_TYPE_BULK * STM32_USB_EPR_EP_TYPE_CONTROL * STM32_USB_EPR_EP_TYPE_ISO * STM32_USB_EPR_EP_TYPE_INTERRUPT * unsigned int wdUserEndPSize= 8,16,32,64 etc ********************************************************************** */ void stm32_usb_pre_reset_setup(unsigned int wdUserEndPNum,\ unsigned int wdUserEndPType,\ unsigned int wdUserEndPSize) { volatile unsigned int *ptrTemp, wdLclPktAddr; /*set usb buffer table address*/ (*PTR_STM32_USB_BTABLE) = 0; /*offset ?*/ /*clear out all packet buffer memory*/ tclib_memset((unsigned char *)PTR_STM32_USB_EPRAM, 0, 0x200); /*initialize control endpoint first - calculate pk buffer local addr*/ ptrTemp = (volatile unsigned int *)PTR_STM32_USB_EPRAM; wdLclPktAddr = ((8 * 8) + 0); /*offset ?*/ /*control endp*/ wdLclPktAddr = stm32_usb_build_endp_descriptors(0,\ STM32_USB_EPR_EP_TYPE_CONTROL,\ STMUSB_ENDP_CTRL_SIZE,\ (unsigned int *)ptrTemp,\ wdLclPktAddr); stm32_usb_enable_endp(0, STM32_USB_EPR_EP_TYPE_CONTROL); /*user chosen endp*/ ptrTemp += (4 * STMUSB_ENDP_USER_NUM); wdLclPktAddr = stm32_usb_build_endp_descriptors(wdUserEndPNum,\ wdUserEndPType,\ wdUserEndPSize,\ (unsigned int *)ptrTemp,\ wdLclPktAddr); stm32_usb_enable_endp(wdUserEndPNum, wdUserEndPType); /*finally set and enable device addr*/ (*PTR_STM32_USB_DADDR) = ((STM32_USB_DADDR_EF) | 0); /*cancel all transfers*/ stm32_usb_cancel_queued_IN_transfers(0); stm32_usb_cancel_queued_IN_transfers(wdUserEndPNum); } /* ********************************************************************** *description: usb routine to build a particular endpoints descriptors * *inputs: unsigned int wdEndPNum = endpoint number * unsigned int wdEndPType= endpoint type * STM32_USB_EPR_EP_TYPE_BULK * STM32_USB_EPR_EP_TYPE_CONTROL * STM32_USB_EPR_EP_TYPE_ISO * STM32_USB_EPR_EP_TYPE_INTERRUPT * unsigned int wdEndPSize= 8,16,32,64 etc *output: wdLclPktAddr = usb local packet address *NOTE: packet descriptor size must be pktsize+2 to account for * the two byte crc the host writes ********************************************************************** */ int stm32_usb_build_endp_descriptors(unsigned int wdEndPNum,\ unsigned int wdEndPType,\ unsigned int wdEndPSize,\ unsigned int *ptrDescAddr,\ unsigned int wdLclPktAddr) { volatile unsigned int wdTemp; /*set tx buffer addr*/ (*ptrDescAddr++) = wdLclPktAddr; wdLclPktAddr += wdEndPSize; /*set tx count*/ (*ptrDescAddr++) = wdEndPSize; /*adjust wdEndPSize to account for extra 2 bytes of crc*/ /*set rx buffer addr*/ wdEndPSize += 2; (*ptrDescAddr++) = wdLclPktAddr; wdLclPktAddr += wdEndPSize; if(wdEndPSize >= 64) { wdTemp = STM32_USB_COUNT_RX_BL_SIZE_32BYTE; wdTemp |= ((wdEndPSize >> 6) << STM32_USB_COUNT_RX_NUM_BLOCK_OFFSET); } else { wdTemp = STM32_USB_COUNT_RX_BL_SIZE_2BYTE; wdTemp |= ((wdEndPSize >> 1) << STM32_USB_COUNT_RX_NUM_BLOCK_OFFSET); } /*set rx count*/ (*ptrDescAddr++) = wdTemp; return wdLclPktAddr; } /* ********************************************************************** *description: usb endpoint send packet routine * *inputs: unsigned int wdEndPNum = endpoint number * unsigned int wdEndPSize= 8,16,32,64 etc * char *ptrBuffer= pointer to buffer * unsigned int wdBytelen = byte length *output: number of bytes sent on success -1 on error (timeout) *note: clears CTR_TX flag ********************************************************************** */ int stm32_usb_endp_send_packet(unsigned int wdEndPNum,\ unsigned char *ptrBuffer,\ unsigned int wdEndPSize,\ unsigned int wdBytelen) { volatile unsigned int wdTemp, *ptrTemp, wdCount, *ptrDst, wdSize; unsigned short int *ptrSrc; ptrSrc = (unsigned short int *)ptrBuffer; if(wdBytelen > wdEndPSize) wdCount = wdEndPSize; else wdCount = wdBytelen; wdSize = wdCount; /* ************************************************************** *copy the data into the buffer - retrieve address *update transmission count *now enable transmission control reg - retrieve value *prepare for transmission - set status bits ************************************************************** */ ptrTemp = (volatile unsigned int *)PTR_STM32_USB_EPRAM; ptrTemp += (4 * wdEndPNum); wdTemp = (*ptrTemp); wdTemp = (PTR_STM32_USB_EPRAM + (wdTemp << 1)); ptrTemp += 1; /*tx count descriptor*/ (*ptrTemp) = wdCount; ptrDst = (unsigned int *)wdTemp; while(wdCount > 0) { *(ptrDst++) = (int)(*(ptrSrc++)); if(wdCount >= 2) wdCount -= 2; else wdCount -= 1; } /* ********************************************************************** *prepare for new transmission at a later time, set valid bits ********************************************************************** */ stm32_usb_set_epr_stat(wdEndPNum,\ STM32_USB_EPR_STAT_TX_VALID,\ STM32_USB_EPR_STAT_TX_OFFSET); return wdSize; } /* ********************************************************************** *description: usb endpoint get packet routine * *inputs: unsigned int wdEndPNum = endpoint number * char *ptrBuffer= pointer to buffer * unsigned int wdBytelen = byte length *output: int = size of data posted *note: clears CTR_RX flag ********************************************************************** */ int stm32_usb_endp_get_packet(unsigned int wdEndPNum,\ unsigned char *ptrBuffer,\ unsigned int wdBytelen) { volatile unsigned int wdTemp, *ptrTemp, wdCount, wdSize ,*ptrSrc; unsigned short int *ptrDst; /* ********************************************************************** *get byte size *copy over data ********************************************************************** */ ptrTemp = (volatile unsigned int *)PTR_STM32_USB_EPRAM; ptrTemp += (4 * wdEndPNum); ptrTemp += 2; wdTemp = (*ptrTemp); wdTemp = (PTR_STM32_USB_EPRAM + (wdTemp << 1)); wdCount = *(ptrTemp +1); wdCount &= STM32_USB_COUNT_RX_MASK; wdSize = wdCount; if(wdCount > wdBytelen) wdCount = wdBytelen; ptrSrc = (unsigned int *)wdTemp; ptrDst = (unsigned short int *)ptrBuffer; while(wdCount > 0) { *(ptrDst++) = (short int)(*(ptrSrc++)); if(wdCount >= 2) wdCount -= 2; else wdCount -= 1; } /* ********************************************************************** *prepare for new reception at a later time, set valid bits ********************************************************************** */ stm32_usb_set_epr_stat(wdEndPNum,\ STM32_USB_EPR_STAT_RX_VALID,\ STM32_USB_EPR_STAT_RX_OFFSET); return wdSize; }
Saturday, August 10, 2013
my style.txt file from 2001
So I found my style.txt file from 2001. It was basically a document I put together defining or clarifying the style I would use in developing software - from variable names to indentation.
Pulled from the way back machine. For the most part I have adhered to this convention all these years and its served me well.
Pulled from the way back machine. For the most part I have adhered to this convention all these years and its served me well.
Samuel Igwe Last Modified: April 6,2001 REVISION OF CODING STYLE ************************ C language and ASM ****************** HEADER (header and function): ***************************** all source files (.asm,.c etc) must have a header that defines its purpose all functions must have a header that defines its purpose as well. this header takes the following form source module header /************************************************************************ module: ... date: ... description: ... ************************************************************************/ function header /************************************************************************ description: ... input: ... output: ... ************************************************************************/ FOR .asm replase /* with ;* or ;- note header top and bottom must start from one end of the screen and end in the other sort of enclosing the function/procedure or header VARIABLES: ********** variables must begin with the following prefixes then the first char capital by=char,byte sb=char array wd=short int,word sw=short int array dw=long,double word sd=long array qw=quad word ptr=pointer str=structure un=union examples of variable names are byChar,wdCount,dwValue,ptrToken, etc FUNCTION and PROCEDURES (definitions): ************************************** function names must begin with the prefix "func" followed by an underbar and then the name of the function. examples of function names are func_get_key, func_init_registers FOR .asm this convention maybe broken in the case of modules that serve as library files (cg=color graphics module). the keyboard library procedures would begin with kb_ the video vga_ etc etc #DEFINE and #EQUATES: ********************* the name of constants defined using the #define prefix must be capitalized for asm, macro names must be capitalized along with equates defined with the .equ directive. examples are #define MAX_STRING_LENGTH 256 .equ BOOTSTART 0 POINTERS (definitions): *********************** all pointer definitions must begin with the prefix "ptr" followed by the name of the pointer. values passed to functions as pointers must be named ptrVariable name even if the original definition was not of a pointer but of an array or variable. examples are ptrToken, ptrChar AESTETHICS: *********** it is far easier to modify code when its appearance pleases the eye and is found understandable. in keeping with this belief, code must be formatted and indented well. examples if=the STATEMENT portion for "if" and "else" MUST be indented (tab) while=same as above do while etc etc this rule applied double to ASM -- blocks of code and loops MUST be indented well -- this rule is sacrosant!!!
Thursday, August 8, 2013
Makefile
CC = arm-linux-gnueabi-gcc LD = arm-linux-gnueabi-ld OBJCPY = arm-linux-gnueabi-objcopy APP = usb #APP = core #CFLAGS = -g -c -Wall -nostdlib -mcpu=cortex-m3 -mlittle-endian -mthumb -I core/include -I tclib \ # -mabi=atpcs -O0 -DDEBUG CFLAGS = -g -c -Wall -nostdlib -mcpu=cortex-m3 -mlittle-endian -mthumb -I core/include -I tclib \ -mabi=atpcs -DDEBUG LDFLAGS= -nostdlib -e main -Map flash.map -L linker -T IE_stm32.ld --cref all: make stm32_core make app make clean stm32_core: $(CC) -o reset.o $(CFLAGS) core/src/IE_stm32_ivt.S $(CC) -o tclibS.o $(CFLAGS) tclib/IE_tclib.S $(CC) -o tclibC.o $(CFLAGS) tclib/IE_tclib.c $(CC) -o usbdev.o $(CFLAGS) core/src/IE_stm32_usb.c $(CC) -o core.o $(CFLAGS) core/src/IE_stm32.c app: $(CC) -o $(APP)_test.o $(CFLAGS) apps/$(APP)/$(APP)_test.c $(LD) -o $(APP)_test.out $(LDFLAGS) reset.o \ core.o \ tclibS.o \ tclibC.o \ usbdev.o \ $(APP)_test.o clean: rm -f reset.o rm -f core.o rm -f tclibS.o rm -f tclibC.o rm -f usbdev.o rm -f $(APP)_test.o binimage: $(OBJCPY) -O binary flash.out flash.bin
Monday, August 5, 2013
IE_tclib.S
/* ***************************************************************** *name: tclib.S *author: Samuel Igwe *date: 08/04/2013 *description: my thumb2 library. asm optimized generic routines * *notes: from ARM technical reference manual * instructions are conditional * eq/ne (eq = 0, ne = not 0) * ge/gt/le/lt * memory addressing formats ldr(s)/str * pre-index with writeback ldr r0, [r1,#4]! * data = mem[base+offset] * base addr reg= base+offset * pre-index ldr r0, [r1,#4] * data = mem[base+offset] * base addr reg= not updated * post-index ldr r0, [r1],#4 * data = mem[base] * base addr reg= base+offset * * #4 above could be replaced by another register ***************************************************************** */ .thumb .text .syntax unified .align 2 .global tclib_cinit .thumb_func .equ SRAM_TOP, (0x20000000 + (20*1024)) tclib_cinit: ldr sp, =SRAM_TOP mov pc, lr /* ***************************************************************** *description: software divider. meanth to be called from asm * takes *inputs: r0 = dividend * r1 = divisor *outputs: r0 = quotient * r1 = remainder *output: 0 on error 1 on success ***************************************************************** */ .align 2 .global tclib_softdiv .thumb_func tclib_softdiv: push {r2, lr} mov r2, r0 /*put r0 in r2*/ mov r0, #0 /*zero out quotient*/ tclib_softdiv_loop: cmp r2, r1 blt tclib_softdiv_exit sub r2, r2, r1 add r0, r0, #1 b tclib_softdiv_loop tclib_softdiv_exit: mov r1, r2 /*r1 remainder*/ pop {r2, lr} mov pc, lr /* ***************************************************************** *description: acquire semaphore *input: char *ptrWord = pointer to memory word *output: 0 on error 1 on success *void *tclib_acquire_semaphore(unsigned char *ptrWord) ***************************************************************** */ .align 2 .global tclib_acquire_semaphore /* ***************************************************************** *r0 = ptrWord ***************************************************************** */ .thumb_func tclib_acquire_semaphore: push {r1-r2} mov r1, #1 mov r2, r0 ldrexb r0, [r2] /*get value*/ cmp r0, #0 eorne r0, #1 bne tclib_get_mutex_exit strexb r0, r1, [r2] eor r0, #1 tclib_get_mutex_exit: clrex pop {r1-r2} mov pc, lr /* ***************************************************************** *description: release semaphore *input: char *ptrWord = pointer to memory word *output: 0 on error 1 on success *void *tclib_release_semaphore(unsigned char *ptrWord) ***************************************************************** */ .align 2 .global tclib_release_semaphore /* ***************************************************************** *r0 = ptrWord ***************************************************************** */ .thumb_func tclib_release_semaphore: push {r1-r2} mov r1, #0 mov r2, r0 ldrexb r0, [r2] /*get value*/ cmp r0, #0 eorne r0, #1 beq tclib_release_mutex_exit strexb r0, r1, [r2] eor r0, #1 tclib_release_mutex_exit: clrex pop {r1-r2} mov pc, lr /* ***************************************************************** *description: sets a string buffer to a certain value *input: char *ptrString =pointer to string * int wdValue =value * int wdSize =maximum length of string *void *tclib_memset(unsigned char *ptrString, int wdValue, int wdSize) *{ *while ((wdSize--) >0) * *(ptrString++) = (char)wdValue; *} ***************************************************************** */ .align 2 .global tclib_memset /* ***************************************************************** *r0 = ptrString *r1 = wdValue *r2 = wdSize *r3 = scratch ***************************************************************** */ .thumb_func tclib_memset: push {r0-r3, lr} mov r3, r1, lsl #8 orr r1, r1, r3 /*put byte into word*/ mov r3, r1, lsl #16 orr r1, r1, r3 /*put word into dword*/ /* ***************************************************************** *the instructions below orr r1, r1, lsl #8 orr r1, r1, lsl #16 * *generate the error tclib/tclib.S: Assembler messages: tclib/tclib.S:203: Error: garbage following instruction -- `orr r1,r1,lsl#8' tclib/tclib.S:204: Error: garbage following instruction -- `orr r1,r1,lsl#16' *under arm-linux-gnueabi-gcc version 4.4.5 *so I revised it to the instructions above this comment ***************************************************************** */ andS r3, r0, #0x3 /*determine dword alignment*/ beq tclib_memset_loop /*take action if aligned*/ tclib_memset_align: strb r1, [r0], #1 /*store one byte - autoincr*/ subS r2, r2, #1 /*decrement counter*/ popeq {r0-r3, lr} /*exit*/ moveq pc, lr /*exit*/ andS r3, r0, #0x3 /*determine dword alignment*/ bne tclib_memset_align tclib_memset_loop: /*optimization*/ cmp r2, #4 /*r2 >= 4*/ blt tclib_memset_align /*else*/ str r1, [r0], #4 /*dword*/ subS r2, #4 /*decrement counter*/ bne tclib_memset_loop pop {r0-r3, lr} /*exit*/ mov pc, lr /*exit*/ /* ***************************************************************** *description: copy from source to destination buffer *input: char *ptrDstStr =pointer to dst string * char *ptrSrcStr =pointer to src string * int wdSize =max length of string *void *tclib_memcpy(unsigned char *ptrDstStr,\ * unsigned char *ptrSrcStr, \ * int wdSize) *{ *while ((wdSize--) >0) * *(ptrDstStr++) = *(ptrSrcStr++); *} ***************************************************************** */ .align 2 .global tclib_memcpy /* ***************************************************************** *r0 = ptrDst *r1 = ptrSrc *r2 = wdSize *r3 = scratch ***************************************************************** */ .thumb_func tclib_memcpy: push {r0-r3, lr} andS r3, r0, #0x3 /*check if dst aligned*/ bne tclib_memcpy_bcopy andS r3, r1, #0x3 /*check if src aligned*/ bne tclib_memcpy_bcopy tclib_memcpy_loop: /*optimization*/ cmp r2, #4 /*check if size >= 4*/ blt tclib_memcpy_bcopy /*else*/ ldr r3, [r1], #4 /*get from src*/ str r3, [r0], #4 /*put in dst*/ subS r2, #4 /*decrement counter*/ bne tclib_memcpy_loop pop {r0-r3, lr} /*exit*/ mov pc, lr /*exit*/ tclib_memcpy_bcopy: ldrb r3, [r1], #1 /*get from src*/ strb r3, [r0], #1 /*put in dst*/ subS r2, #1 /*decrement counter*/ bne tclib_memcpy_bcopy pop {r0-r3, lr} /*exit*/ mov pc, lr /*exit*/ /* ***************************************************************** *description: ascii to integer *input: char *ptrAscStr =pointer to string *output: int =value *int *tclib_atoi(unsigned char *ptrAscStr) *{ *unsigned char *ptrTemp; *volatile int wdValue,wdWeight,wdTemp; * *wdValue =0; *wdWeight=1; *ptrTemp =ptrAscStr; * *while ((*ptrTemp) != NULL) * ptrTemp++; * *while ((--ptrTemp) >= ptrAscStr) * { * wdTemp = *ptrTemp; * if (wdTemp >= '0' && wdTemp <='9') * wdTemp-= '0'; * else * { * if (wdTemp >='a' && wdTemp <='f') * { * wdTemp-= 'a'; * wdTemp+= 10; * } * else * { * if (wdTemp >= 'A' && wdTemp <= 'F') * { * wdTemp-= 'A'; * wdTemp+= 10; * } * else * return 0; * } * } * * wdValue += wdTemp * wdWeight; * wdWeight<<= 4; * } * *return wdValue; *} ***************************************************************** */ .align 2 .global tclib_atoi /* ***************************************************************** *r0 = ptrString *returns r0 *r1 = r0 - address *r2 = scratch - wdValue *r3 = scratch - wdWeight *r4 = scratch ***************************************************************** */ .thumb_func tclib_atoi: push {r1-r4, lr} mov r1, r0 /*to be return value*/ bl tclib_strlen /*of strlen()*/ cmp r0, #0 /*is it zero?*/ pop {r1-r4, lr} moveq pc, lr mov r3, #1 /*init wdWeight*/ mov r2, #0 /*zero out*/ tclib_atoi_loop: subS r0, r0, #1 /*decrement loop*/ movlt r0, r2 /*copy out arg when done*/ poplt {r1-r4, lr} movlt pc, lr ldrb r4, [r1,r0] /*preindex without update*/ and r4, r4, #0x0ff /*clear upper bits*/ cmp r4, #'0' movlt r0, #0 /*zero out before exiting*/ poplt {r1-r4, lr} /*exit if less than '0'*/ movlt pc, lr /*exit*/ cmp r4, #'9' bgt tclib_atoi_lcase sub r4, r4, #'0' mla r2, r4, r3, r2 /*r2=(r3*r4)+r2*/ mov r3, r3, lsl #4 /*adjust 16^x*/ b tclib_atoi_loop tclib_atoi_lcase: cmp r4, #'a' blt tclib_atoi_ucase cmp r4, #'f' movgt r0, #0 /*zero out before exiting*/ popgt {r1-r4, lr} /*exit if greater than 'f'*/ movgt pc, lr /*exit*/ sub r4, r4, #'a' add r4, r4, #10 mla r2, r4, r3, r2 /*r2=(r3*r4)+r2*/ mov r3, r3, lsl #4 b tclib_atoi_loop tclib_atoi_ucase: cmp r4, #'A' movlt r0, #0 /*zero out before exiting*/ poplt {r1-r4, lr} movlt pc, lr cmp r4, #'F' movgt r0, #0 /*zero out before exiting*/ popgt {r1-r4, lr} /*exit if greater than 'F'*/ movgt pc, lr /*exit*/ sub r4, r4, #'A' add r4, r4, #10 mla r2, r4, r3, r2 /*r2=(r3*r4)+r2*/ mov r3, r3, lsl #4 b tclib_atoi_loop /* ***************************************************************** *description: integer to ascii. convert nibbles *input: int wdValue =value * char *ptrAscStr =pointer to string *void *tclib_itoa(int wdValue, unsigned char *ptrAscStr) *{ *volatile int wdIndex,wdTemp; * *if (wdValue < 0) * wdIndex =8; *else * { * if (wdValue < (1 << 8)) * wdIndex =2; * else * { * if (wdValue < (1 << 16)) * wdIndex =4; * else * { * if (wdValue < (1 << 24)) * wdIndex =6; * else * wdIndex =8; * } * } * } * *ptrAscStr[wdIndex--] =NULL; *while (wdIndex >=0) * { * wdTemp = wdValue; * wdTemp &= 0x0f; * wdValue>>= 4; * * if (wdTemp >=0 && wdTemp < 10) * ptrAscStr[wdIndex--] = wdTemp +'0'; * else * { * wdTemp -=10; * ptrAscStr[wdIndex--] = wdTemp +'A'; * } * } *} ***************************************************************** */ .align 2 .global tclib_itoa /* ***************************************************************** *r0 = value *r1 = ptrString *r2 = scratch - index *r3 = scratch *r4 = 1 ***************************************************************** */ .thumb_func tclib_itoa: push {r0-r4, lr} mov r4, #1 mov r3, r4, lsl #8 /*(wdValue< (1<<8))*/ cmp r0, r3 movlo r2, #2 blo tclib_itoa_prep_loop mov r3, r4, lsl #16 /*(wdValue< (1<<16))*/ cmp r0, r3 movlo r2, #4 blo tclib_itoa_prep_loop mov r3, r4, lsl #24 /*(wdValue< (1<<24))*/ cmp r0, r3 movlo r2, #6 movhs r2, #8 tclib_itoa_prep_loop: add r1, r1, r2 /*setup addresses*/ mov r3, #0 strb r3, [r1],#-1 /*nullify string*/ tclib_itoa_loop: sub r2, r2, #1 /*decrement counter*/ cmp r2, #0 poplt {r0-r4, lr} /*exit*/ movlt pc, lr /*exit*/ mov r3, r0 /*save r0 temporarily*/ mov r0, r0, lsr #4 /*new value to work on*/ and r3, r3, #0x0f /*nibble*/ cmp r3, #10 /*prepare to adjust*/ addlt r3, r3, #'0' subge r3, r3, #10 addge r3, r3, #'A' strb r3, [r1],#-1 /*store with auto-decr*/ b tclib_itoa_loop /* ***************************************************************** *description: word swap *input: int wdValue = value *output: int *int *tclib_word_swap(int wdValue) *{ *unsigned int dwTemp; * *(dwTemp = 0; *dwTemp|= (wdValue << 24) & 0xff000000; *dwTemp|= (wdValue << 8 ) & 0x00ff0000; *dwTemp|= (wdValue >> 24) & 0x0ff; *dwTemp|= (wdValue >> 8 ) & 0x0ffff; * *return dwTemp; *} ***************************************************************** */ .align 2 .global tclib_swap /* ***************************************************************** *r0 = value *returns r0 = word swapped value *r1 = scratch *r2 = scratch *r3 = 0x0ff ***************************************************************** */ .thumb_func tclib_swap: push {r1, lr} mov r1, r0 /*safe keep - r0 = return*/ rev r0, r1 /*theres a single thumb ins*/ /*for this now*/ pop {r1, lr} /*exit*/ mov pc, lr /*exit*/ /* ***************************************************************** *description: byte swap *input: int wdValue = value *output: int *int *tclib_byte_swap(int wdValue) *{ *unsigned int dwTemp; * *dwTemp = 0; *dwTemp|= (wdValue << 8 ) & 0xff00; *dwTemp|= (wdValue >> 8 ) & 0x0ff; * *return dwTemp; *} ***************************************************************** */ .align 2 .global tclib_bswap /* ***************************************************************** *r0 = value *returns r0 = byte swapped value *r1 = scratch *r2 = scratch old value ***************************************************************** */ .thumb_func tclib_bswap: push {r1, lr} mov r1, r0 rev r0, r1 /*save original value*/ mov r0, r0, lsl #16 pop {r1, lr} /*exit*/ mov pc, lr /*exit*/ /* ***************************************************************** *description: string len computation function *inputs: char *ptrStrSrc *output: int = lenght of string *int *tclib_strlen(unsigned char *ptrStrSrc) *{ *unsigned int wdCount; *for (wdCount=0; ptrStrSrc[wdCount]!=NULL; wdCount++) * ; * *return wdCount; *} ***************************************************************** */ .align 2 .global tclib_strlen /* ***************************************************************** *r0 = ptrString *returns r0 = byte length *r1 = ptrString *r2 = scratch ***************************************************************** */ .thumb_func tclib_strlen: push {r1-r2, lr} mov r1, r0 /*put pointer in r1*/ mov r0, #0 /*zero out r0*/ tclib_strlen_loop: ldrb r2, [r1], #1 andS r2, r2, #0x0ff /*clear lower bits*/ addne r0, r0, #1 /*track strlen results*/ popeq {r1-r2, lr} /*exit*/ moveq pc, lr /*exit*/ b tclib_strlen_loop /* ***************************************************************** *description: string comparison *inputs: char *ptrStrSrc=string 1 * char *ptrStrDst=string 2 * int wdCount =number of characters to compare *output: int = 0 on success failing index on error *int *tclib_strcmp(unsigned char *ptrStrSrc,\ * unsigned char *ptrStrDst,\ * int wdCount) *{ *unsigned int wdIndex; * *for(wdIndex=0; wdIndex <wdCount; wdIndex++) * { * if (ptrStrSrc[wdIndex] == NULL || \ * ptrStrDst[wdIndex] == NULL || \ * (ptrStrSrc[wdIndex] - ptrStrDst[wdIndex]) !=0) * return wdIndex; * } * *return 0; *} ***************************************************************** */ .align 2 .global tclib_strcmp /* ***************************************************************** *r0 = ptrDst *r1 = ptrSrc *returns r0 strcmp value *r1 = src1 *r2 = src2 *r3 = scratch *r4 = scratch *r0 = cmp ***************************************************************** */ .thumb_func tclib_strcmp: push {r1-r4, lr} mov r2, r0 /*save src1 in r2*/ mov r0, #0 /*zero out r0*/ tclib_strcmp_loop: ldrb r3, [r1], #1 andS r3, r3, #0x0ff /*clear upper bits*/ ldrb r4, [r2], #1 andS r4, r4, #0x0ff /*clear upper bits*/ cmp r3, r4 addeq r0, r0, #1 /*track strcmp results*/ beq tclib_strcmp_cmp_zero popne {r1-r4, lr} /*exit*/ movne pc, lr /*exit*/ tclib_strcmp_cmp_zero: orrS r4, r3, r4 /*are both zero?*/ moveq r0, #0 /*return 0*/ popeq {r1-r4, lr} /*exit*/ moveq pc, lr /*exit*/ b tclib_strcmp_loop .end
Subscribe to:
Posts (Atom)