Micro Python: Python for microcontrollers 
The Python language made lean and fast to run on microcontrollers. For beginners and experts, control your electronic project with ease.


[ 2 comments ]   |  [ 0 trackbacks ]   |  permalink  |  related link
STM32f4 Discovery driver using I2C Interface to communicate with 1602/HD44780 LCD 
The code below is working STM32f4 driver for an 1602 LCD equipped with HD44780 controller which uses IIC I2C Serial Interface Board Module.



useful links: physical connections, IIC I2C Serial Interface

support_nej.h:
#include <stdint.h>

void lcd_i2c_init( void );
void lcd_i2c_pulse( uint8_t _data );

void lcd_command( uint8_t value );
void lcd_data( uint8_t value );
void lcd_send( uint8_t value, uint8_t mode );

void delay_ms( uint32_t _delay );
void lcd_command_clear( void );
void lcd_simple_print( const char *str );
void lcd_printf( const char *format, ... );

void lcd_i2c_pulse( uint8_t _data );



support_nej.c:
// support for 1602 LCD display ( 2 x 16 characters )
// equipped with HD44780 controller.
// tested on STM32f4 Discovery
//

#include <stdio.h>
#include <stdbool.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdint.h>

#include "support_nej.h"
#include "support_nej_i2c.h"
#include "support_nej_lcd.h"

#define I2C_LCD_SLAVE_ADDRESS 0x20

// Keil compiler does not support bit notation (aka 0b00..)
// the following define adds the missing functionality
#define BIN_TO_BYTE(b7,b6,b5,b4,b3,b2,b1,b0) \
((b7 << 7)+(b6 << 6)+\
(b5 << 5)+(b4 << 4)+\
(b3 << 3)+(b2 << 2)+\
(b1 << 1)+b0)


// LCD definitions
//
//
//

// HD44780 controller functions
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80

// flags for LCD_ENTRYMODESET
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00

// flags for LCD_DISPLAYCONTROL
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00

// flags for LCD_CURSORSHIFT
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00

// flags for LCD_FUNCTIONSET
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_1LINE 0x00
#define LCD_2LINE 0x08
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00


// master pins
#define LCD_BACKLIGHT_ON BIN_TO_BYTE(0,0,0,0,0,0,0,0) // ON = data is LOW
#define LCD_BACKLIGHT_OFF BIN_TO_BYTE(1,0,0,0,0,0,0,0) // OFF = data is HIGH

#define LCD_RS_DATA BIN_TO_BYTE(0,1,0,0,0,0,0,0) // DATA (write to CGRAM/DDRAM)
#define LCD_RS_COMMAND BIN_TO_BYTE(0,0,0,0,0,0,0,0) // COMMANDS

#define LCD_RW_HIGH BIN_TO_BYTE(0,0,1,0,0,0,0,0) // READ from LCD
#define LCD_RW_LOW BIN_TO_BYTE(0,0,0,0,0,0,0,0) // WRITE to LCD (character or command)

#define LCD_PULSE_HIGH BIN_TO_BYTE(0,0,0,1,0,0,0,0) // Enable Pulse on pin 6
#define LCD_PULSE_LOW BIN_TO_BYTE(0,0,0,0,0,0,0,0) // when pulse goes from high to low the data is read


// COMMANDS: set DDRAM address ( display 2 x 16 )
#define LCD_CURSOR_LINE_MAX 15
#define LCD_CURSOR_TO_LINE_1 BIN_TO_BYTE(1,0,0,0,0,0,0,0)
#define LCD_CURSOR_TO_LINE_2 BIN_TO_BYTE(1,1,0,0,0,0,0,0)


// ASCII definitions for CR (\r) and LF (\n)
// used in printf
#define ASCII_CARRIAGE_RETURN 0x0d
#define ASCII_LINE_FEED 0x0a


// small buffer for prinf formatting
#define PRINT_BUFFER_SIZE 64


// lcd_simple_print and lcd_printf are function for
// text output on the i2c connected display
//
//
void lcd_simple_print( const char *str )
{
uint8_t _cursor_position = 0;

lcd_command_clear();

while( *str ) {

_cursor_position++;
if( _cursor_position > LCD_CURSOR_LINE_MAX | *str == ASCII_LINE_FEED )
{
lcd_command( LCD_CURSOR_TO_LINE_2 );
_cursor_position = 0;
str++;
} else
{
lcd_data( *str );
str++;
}

}
}


void lcd_printf( const char *format, ... )
{
va_list args;
char *buf = ( char *) malloc( PRINT_BUFFER_SIZE * sizeof( char ) );

if( buf != 0 )
{
va_start( args, format );

if( vsnprintf( buf, PRINT_BUFFER_SIZE * sizeof( char ), format, args ) > 0 )
{
lcd_simple_print( buf );
} else
{
lcd_simple_print( buf );
lcd_simple_print( "lcd_printf: maxlen \
character limit was reached or some other error, \
such as an invalid format specification\n" );
}

va_end( args );
free( buf );

} else
{
lcd_simple_print( "lcd_printf: not enough memory\n" );
}
}


// some simple delay, should use timer
//
void delay_ms( uint32_t _time )
{
_time = _time * 420;

while( _time-- )
{
}
}


// abstract functions
// concept taken from arduino I2C LCD library
//
//
void lcd_command( uint8_t value )
{
lcd_send( value, LCD_RS_COMMAND );
}

void lcd_command_clear( void )
{
lcd_command( LCD_CLEARDISPLAY );
delay_ms( 100 );
}

void lcd_data( uint8_t value )
{
lcd_send( value, LCD_RS_DATA );
}


// convert function for 4-bit communication
// writes either command or data
//
//
void lcd_send( uint8_t value, uint8_t mode )
{
uint8_t high_nibble = ( value>>4 ) & 0x0f;
uint8_t low_nibble = ( value ) & 0x0f;

lcd_i2c_pulse( high_nibble | mode );
lcd_i2c_pulse( low_nibble | mode );
}


// the "pulse" function simulates the ramp ON/OFF
// the controller reads data when the LCD_PULSE pin
// goes from HIGH to LOW
//
void lcd_i2c_pulse( uint8_t _data )
{
I2C_start( I2C1, I2C_LCD_SLAVE_ADDRESS<<1, I2C_Direction_Transmitter );
I2C_write( I2C1, (uint8_t) ( _data ) );
I2C_stop( I2C1 );

I2C_start( I2C1, I2C_LCD_SLAVE_ADDRESS<<1, I2C_Direction_Transmitter );
I2C_write( I2C1, (uint8_t) ( _data ) | LCD_PULSE_HIGH );
I2C_stop( I2C1 );

I2C_start( I2C1, I2C_LCD_SLAVE_ADDRESS<<1, I2C_Direction_Transmitter );
I2C_write( I2C1, (uint8_t) ( _data ) );
I2C_stop( I2C1 );
}


// sets the controller: 4-bit communication
// interaction with 1602 LCD
//
//
void lcd_i2c_init( void )
{
// switch controller to 8bit mode, regardless the mode
// the controller is in. there should be waits added
// 5ms for command writes and 200us for data writes.

lcd_i2c_pulse( 0x03 );
lcd_i2c_pulse( 0x03 );

// LCD in 8-bit mode

lcd_i2c_pulse( 0x03 );

// switch to 4-bit mode
lcd_i2c_pulse( 0x02 );

// controller is in 4-bit mode, configure its behaviour

lcd_command( LCD_FUNCTIONSET | \
LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS );

lcd_command( LCD_DISPLAYCONTROL | \
LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF );

lcd_command( LCD_ENTRYMODESET | \
LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT );
};


[ 180 comments ]   |  [ 0 trackbacks ]   |  permalink
STM32F10xx, STM32F2xx, STM32F4xx and STM32L1xx I2C Communication peripheral application library (CPAL) (UM1029)  
The aim of this application note is to provide I2C firmware optimized examples based on polling, interrupts and DMA, covering the four I2C communication modes available in the STM32F10xxx, that is, slave transmitter, slave receiver, master transmitter and master receiver and to provide recommendations on the correct use of the I2C peripheral.

[ 9 comments ]   |  [ 0 trackbacks ]   |  permalink  |  related link
Four-Bit D/A Converter  


[ 10 comments ]   |  [ 0 trackbacks ]   |  permalink  |  related link
pulse timers  
/* Time 2 base configuration 10ms */
TIM_TimeBaseStructure.TIM_Period = 9999;
TIM_TimeBaseStructure.TIM_Prescaler = 72;
TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

Period calculation:

72MHz / 72 = 1MHz or 1µs period unit.
1µs + 9999 x (1µs) = 10ms


http://guyvo-cortex.blogspot.cz/2009/04 ... imers.html



void TIM4_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

// TIM_TimeBaseStructure.TIM_Prescaler = (800 * 2) - 1; // 8 MHz clock source, 8000 for 2 ms, 800 for 0.2 ms ticks
TIM_TimeBaseStructure.TIM_Prescaler = (7200 * 2) - 1; // 72 MHz clock source, 0.2 ms ticks

TIM_TimeBaseStructure.TIM_Period = 50000 - 1; // 0.2 ms units, 10 second update
TIM_TimeBaseStructure.TIM_ClockDivision = 1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);

// TIM4 enable counter
TIM_Cmd(TIM4, ENABLE);

// Clear pending update interrupt
TIM_ClearITPendingBit(TIM4, TIM_IT_Update);

// Enable interrupt on update
TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
}


https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=https%3a%2f%2fmy.st.com%2fpublic%2fSTe2ecommunities%2fmcu%2fLists%2fcortex_mx_stm32%2fProblem%20with%20Timing&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B&currentviews=1913

[ 3953 comments ]   |  [ 0 trackbacks ]   |  permalink  |  related link
STMicroelectronics: Cortex™-M4 Training STM32F407 
The purpose of this lab is to introduce you to the STMicroelectronics Cortex™-M4 processor using the ARM Keil™ MDK toolkit featuring the IDE μVision. We will use the Serial Wire Viewer (SWV) and the on-board ST-Link V2 Debug Adapter. At the end of this tutorial, you will be able to confidently work with these processors and Keil MDK. See www.keil.com/st.



[ 8 comments ]   |  [ 0 trackbacks ]   |  permalink  |  related link
SysTick IRQ for Audio on STM32f4 Discovery 
Example: to configure Systick - SysTick_Config(SystemCoreClock / IT_PER_SEC) - for having interrupt an specific frequency divide the base clock frequency by required frequency.

ie.: 100 Hz we need
168 Mhz is the chip

168 000 000 / 100 = 1 680 000

it means every 1 680 000 cpu cycles the SysTick interrupt is generated.

for audio, try to generate interrupt for a C8 notewhich is 4186.009Hz.

ie.: 4186.009 * 2 = 8372,018; interrupt is generated for each change in the cycle, there are two changes, from HIGH to LOW or LOW to HIGH.

     168 000 000 / 8372 = ~20067


each 20067 cycles the cycle toggle is invoked.

what would be the most optimal irq frequency up to C9 which is 8372, resp. 16744? the count for this note is 10033 cyces the interrupt is invoked. what is the optimal count of cycles between the interrupt, taking into account the interupt routine also takes cycles?

rough quess: arm does single ol half of the instruction per cycle. cpu needs to run the user program as well at least for the same as it spends with the intr. also we need some spare time to make sure we will not be missing an interrupt.

      1000 * x = 168 000 000
x = 168 000

168 000 times per second we will generate the interrupt. for that number the uint16_t type for the counter var is too small, uint32_t with 4,294,967,295 is enough.

168 000 / 16 744 = 10.003

but the glitch is, the higher frequency we generate, the more it will be inaccurate because of division error. that's why Juno 106 has 1 Mhz / 1 000 000 timer. such precision we can't reach that way.

to have 1 000 000 interrupts (better would be 2 000 000) per sec we wil need the interrupt to be generated each 168 (better 84) cycles. irq routine then has to be cleared out in 84 (42) cycles which obviously will not until rewritten in asm.

a better way how to solve this is to use the independent irq with pulse modulation on a chip.

some reading:

http://www-micrel.deis.unibo.it/LABARCH ... 2/lab4.pdf

http://amarkham.com/?p=29

https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=%2Fpublic%2FSTe2ecommunities%2Fmcu%2FLists%2Fcortex_mx_stm32%2FWhat%20difference%20between%20setting%20TIM_TimeBaseStructure.TIM_Prescaler%20and%20%20TIM_PrescalerConfig&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B&currentviews=256

http://visualgdb.com/tutorials/arm/stm32/timers/

http://myembeddedtutorial.blogspot.cz/2 ... imers.html

http://code.google.com/p/andrei-develop ... ain.c?r=34


[ add comment ]   |  [ 0 trackbacks ]   |  permalink  |  related link
STM32f4 USART routine (echoes input) works 
- clock to peripherials, of course
- peripherial structures can be set to default values prior to fill them with custom values
- clock for USARTx/UARTs must be configured
- IRQ handler has to clear the IRQ flags
- NVIC must be configured
- USART_ITConfig must be configured accordingly to allow trigger intr

in this code
- no lame putchar redirection, but the function which behaves like printf
- buffer created each time for a line written (uneffective, but the irq wont erase the previous unprinted message)
* implement buffer, no ring, but specific array-pointer with buffer full functionality, use dma for input and output, play with priorities to maintain the smooth systick.



#include <misc.h>

#define PRINT_BUFFER_SIZE 64


/*******************************************************************
* USART/UARTx: usart_simple_print( USART_TypeDef *usart, const char *str )
* usart_printf( USART_TypeDef *usart, const char *format, ... )
*******************************************************************/
void usart_simple_print( USART_TypeDef *usart, const char *str )
{
while( *str ) {
while( USART_GetFlagStatus( usart, USART_FLAG_TXE) == RESET );
USART_SendData( usart, *str );
str++;
}
}


void usart_printf( USART_TypeDef *usart, const char *format, ... )
{
va_list args;
char *buf = ( char *) malloc( PRINT_BUFFER_SIZE * sizeof( char ) );

if( buf != 0 )
{
va_start( args, format );

if( vsnprintf( buf, PRINT_BUFFER_SIZE * sizeof( char ), format, args ) > 0 )
{
usart_simple_print( usart, buf );
} else
{
usart_simple_print( usart, buf );
usart_simple_print( usart, "usart_printf: maxlen \
character limit was reached or some other error, \
such as an invalid format specification\n" );
}

va_end( args );
free( buf );
} else
{
usart_simple_print( usart, "usart_printf: not enough memory\n" );
}
}



/*******************************************************************
* usart init
*
*******************************************************************/
void USART_my_init( uint32_t baud )
{

// define structure(s)
GPIO_InitTypeDef GPIO_InitStruct_Rx;
GPIO_InitTypeDef GPIO_InitStruct_Tx;
USART_ClockInitTypeDef USART_ClockInitStruct;
USART_InitTypeDef USART_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;


//
// -----------------------------usart-Rx-pin-B7

// enable clock to peripherial
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

// init (clear to default) this structure
GPIO_StructInit( &GPIO_InitStruct_Rx );

// fill in params
GPIO_InitStruct_Rx.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStruct_Rx.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct_Rx.GPIO_Mode = GPIO_Mode_AF;
//GPIO_InitStruct_Rx.GPIO_Mode = IN_FLOATING;


// make it written
GPIO_Init(GPIOB, &GPIO_InitStruct_Rx);

// assign alternate function to a pin
GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_USART1);

//
// -----------------------------usart-Tx-pin-B6

// enable clock to peripherial
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

// init (clear to default) this structure
GPIO_StructInit( &GPIO_InitStruct_Tx );

// fill in params
GPIO_InitStruct_Tx.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStruct_Tx.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct_Tx.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct_Tx.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct_Tx.GPIO_PuPd = GPIO_PuPd_UP;

// make it written
GPIO_Init(GPIOB, &GPIO_InitStruct_Tx);

// assign alternate function to a pin
GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_USART1);

//
// ---------------------------------usart-clock

// init (clear to default) this structure
USART_ClockStructInit(&USART_ClockInitStruct);

// fill in params
USART_ClockInitStruct.USART_Clock = USART_Clock_Disable;
USART_ClockInitStruct.USART_CPOL = USART_CPOL_High;
USART_ClockInitStruct.USART_LastBit = USART_LastBit_Disable;
USART_ClockInitStruct.USART_CPHA = USART_CPHA_1Edge;

// make it written
USART_ClockInit( USART1, &USART_ClockInitStruct );

//
// ----------------------------usart-parameters

// enable clock to peripherial
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

// init (clear to default) this structure
USART_StructInit( &USART_InitStruct );

// fill in params
// Clock, CPOL_LOW, CPHA_2Edge, LastBit_Disable added
//
// USART synchronous mode:
// CPOL - bit allows the user to select
// the clock polarity
// CPHA - bit allows the user to select the
// phase of the external clock
//
USART_InitStruct.USART_BaudRate = baud;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_Parity = USART_Parity_No;
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; /*send a idle frame,cause TXE=1 interupt*/


// make it written
USART_Init(USART1, &USART_InitStruct);

// enable device
USART_Cmd(USART1, ENABLE);



//
// ----------------------------usart-interrupts

// fill in params
NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;

// make it written
NVIC_Init(&NVIC_InitStruct);

// Enable Transmit intr, transmit data register is empty
USART_ITConfig(USART1, USART_IT_TXE, DISABLE);

// Enable Receive intr, data register is not empty
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

// konec inicializace
usart_printf( USART1, "usart1 inicializace dokoncena\n" );

}




//
// ----------------------------irq-usart-routine
void USART1_IRQHandler(void)
{
unsigned char recdata, temphead;

// usart_printf( USART1, "IN INTERRUPT\n" );

// is USART_IT_ORE_ER (overrun)
//
if(USART_GetITStatus(USART1, USART_IT_ORE_ER) != RESET)
{
usart_printf( USART1, "ErI - overrun error\n" );
}


// is USART_IT_RXNE intr (the shift register is transferred
// to the RDR - data can be read
//
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
USART_ClearITPendingBit(USART1, USART_IT_RXNE);

recdata = USART_ReceiveData( USART1 ) & 0xFF;

// echo recived character
usart_printf( USART1, "%c", recdata );
}

// is USART_IT_TXE intr, send data out
//
if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)
{
USART_ClearITPendingBit(USART1, USART_IT_TXE);

// do we have some data to send
usart_printf( USART1, "TxI\n" );
}


}



/*******************************************************************
* configure LEDs on board
*
*******************************************************************/
void GPIO_my_init() {

GPIO_InitTypeDef GPIO_InitStruct;

//
// ------------------------pin-D15-D14-D13-D12

// enable clock to peripherial
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

// init (clear to default) this structure
GPIO_StructInit( &GPIO_InitStruct );

// fill in params
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_15 | GPIO_Pin_14 | GPIO_Pin_13 | GPIO_Pin_12;
// we want to configure all LED GPIO pins
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; // we want the pins to be an output
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; // this sets the GPIO modules clock speed
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; // this sets the pin type to push / pull (as opposed to open drain)
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; // this sets the pullup / pulldown resistors to be inactive

// make it written
GPIO_Init(GPIOD, &GPIO_InitStruct); // this finally passes all the values to the GPIO_Init function which takes care of setting the corresponding bits.

}





[ 7 comments ]   |  [ 0 trackbacks ]   |  permalink
Oscilloscopes 
This one I want...



This guy I can afford :)


http://www.gme.cz/osciloskop-dvoukanalo ... t-p720-113

[ add comment ]   |  [ 0 trackbacks ]   |  permalink
Windows XP won't update as SVCHOST eats all the CPU cycles 
If the windows update service is run, or the updates are invoked with ms explorer throuhg update page, cpu load goes high.

you may get rid of the problem by installing updaes manually. get usefull utility which allows you to donwload updates by hand and. Grab the list of updates from the same page (after downoading double click on icon). Then run the utility and let it download the updates.

After all is downloaded, then sort the updates by date and start with the manual running each single one. You probably wont have to run all of them, because after some of aupdates are installed, the native autoupdater finally wakes upa and shows the shield icon in the tray without the svchost locking the cupu.



[ add comment ]   |  [ 0 trackbacks ]   |  permalink  |  related link

<<First <Back | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | Next> Last>>