Пример #1
0
 int main(void)
 {
     uint8_t page_address;
     uint8_t column_address;
     uint8_t start_line_address = 0;
     volatile uint16_t delay = 10000;
 
     board_init();
     sysclk_init();
 
     // Initialize SPI and SSD1306 controller
     ssd1306_init();
 
     // set addresses at beginning of display
     ssd1306_set_page_address(0);
     ssd1306_set_column_address(0);
 
     // fill display with lines
     for (page_address = 0; page_address <= 4; page_address++) {
         ssd1306_set_page_address(page_address);
         for (column_address = 0; column_address < 128; column_address++) {
             ssd1306_set_column_address(column_address);
             /* fill every other pixel in the display. This will produce
             horizontal lines on the display. */
             ssd1306_write_data(0x6F);
         }
     }
 
     // scroll the display using hardware support in the LCD controller
     while (true) {
         ssd1306_set_display_start_line_address(start_line_address++);
        clock_delay_msec(250);
     }
 }
Пример #2
0
/**
 * \brief Draw graph on the OLED screen using the provided point array.
 * \param col X coordinate.
 * \param page Y coordinate (please refer to OLED datasheet for page
 * description).
 * \param width Graph width(columns).
 * \param height Graph height(pages, 1~3).
 * \param tab Data to draw. Must contain width elements.
 */
static void ssd1306_draw_graph(uint8_t col, uint8_t page, uint8_t width,
		uint8_t height, uint8_t *tab)
{
	uint8_t i, j;
	uint8_t page_start, scale, bit_length, page_data[3];
	uint32_t bit_data;

	for (i = col; i < width; ++i) {
		scale = 8 * height;
		bit_length = tab[i] * scale / 24;
		for (bit_data = 0; bit_length > 0; --bit_length) {
			bit_data = (bit_data << 1) + 1;
		}
		page_data[0] = bit_reverse8(bit_data & 0xFF);
		page_data[1] = bit_reverse8((bit_data >> 8) & 0xFF);
		page_data[2] = bit_reverse8((bit_data >> 16) & 0xFF);
		j = height - 1;
		for (page_start = page; page_start < (page + height); ++page_start) {
			ssd1306_write_command(SSD1306_CMD_SET_PAGE_START_ADDRESS(
					page_start));
			ssd1306_set_column_address(i);
			ssd1306_write_data(page_data[j]);
			--j;
		}
	}
}
Пример #3
0
/**
 * \brief Draw graph on the OLED screen using the provided point array.
 * \param col X coordinate.
 * \param page Y coordinate (please refer to OLED datasheet for page description).
 * \param width Graph width.
 * \param height Graph height.
 * \param tab Data to draw. Must contain width elements.
 */
static void ssd1306_draw_graph(uint8_t col, uint8_t page, uint8_t width, uint8_t height, uint8_t *tab)
{
	volatile register uint8_t page_start;
	volatile register uint8_t i, j, k, s;
	uint8_t scale;

	for (i = 0; i < width; ++i) {
		for (page_start = page; page_start <= height; ++page_start) {
			ssd1306_write_command(SSD1306_CMD_SET_PAGE_START_ADDRESS(page_start));
			ssd1306_set_column_address(i);
			j = tab[i];
			scale = 8 * (height - page_start + 1);
			if (j > scale)
				j = 8;
			else
				j -= (scale - 8);

			for (k = 0, s = j; j > 0; --j)
				k = (k << 1) + 1;
			for (s = 8 - s; s > 0; --s)
				k <<= 1;
			ssd1306_write_data(k);
		}
	}
}
Пример #4
0
/**
 * \brief Put framebuffer to LCD controller
 *
 * This function will output the complete framebuffer from RAM to the
 * LCD controller.
 *
 * \note This is done automatically if using the graphic primitives. Only
 * needed if you are manipulating the framebuffer directly in your code.
 */
void gfx_mono_ssd1306_put_framebuffer(void)
{
	uint8_t page;

	for (page = 0; page < GFX_MONO_LCD_PAGES; page++) {
		ssd1306_set_page_address(page);
		ssd1306_set_column_address(0);
		gfx_mono_ssd1306_put_page(framebuffer
				+ (page * GFX_MONO_LCD_WIDTH), page, 0,
				GFX_MONO_LCD_WIDTH);
	}
}
Пример #5
0
/**
 * \brief Get a byte from the display controller RAM
 *
 * If the LCD controller is accessed by the SPI interface we cannot read the
 * data. In this case return the data from the local framebuffer instead.
 *
 * \param page Page address
 * \param column Page offset (x coordinate)
 * \return data from LCD controller or framebuffer.
 *
 * The following code will read the first byte from the display memory or the
 * local framebuffer if direct read is not possible. The data represents the
 * pixels from x = 0 and y = 0 to y = 7.
 * \code
 * data = gfx_mono_ssd1306_get_byte(0, 0);
 * \endcode
 */
uint8_t gfx_mono_ssd1306_get_byte(gfx_coord_t page, gfx_coord_t column)
{
#ifdef CONFIG_SSD1306_FRAMEBUFFER
	return gfx_mono_framebuffer_get_byte(page, column);

#else
	ssd1306_set_page_address(page);
	ssd1306_set_column_address(column);

	return ssd1306_read_data();

#endif
}
Пример #6
0
/**
 * \brief Put a page from RAM to display controller.
 *
 * If the controller is accessed by the SPI interface, we can not read
 * back data from the LCD controller RAM. Because of this all data that is
 * written to the LCD controller in this mode is also written to a framebuffer 
 * in MCU RAM.
 *
 * \param data Pointer to data to be written
 * \param page Page address
 * \param column Offset into page (x coordinate)
 * \param width Number of bytes to be written.
 *
 * The following example will write 32 bytes from data_buf to the page 0,
 * column 10. This will place data_buf in the rectangle x1=10,y1=0,x2=42,y2=8
 * (10 pixels from the upper left corner of the screen):
 * \code
 * gfx_mono_ssd1306_put_page(data_buf, 0, 10, 32);
 * \endcode
 */
void gfx_mono_ssd1306_put_page(gfx_mono_color_t *data, gfx_coord_t page,
		gfx_coord_t column, gfx_coord_t width)
{
#ifdef CONFIG_SSD1306_FRAMEBUFFER
	gfx_mono_framebuffer_put_page(data, page, column, width);
#endif
	ssd1306_set_page_address(page);
	ssd1306_set_column_address(column);

	do {
		ssd1306_write_data(*data++);
	} while (--width);
}
Пример #7
0
/**
 * \brief Read a page from the LCD controller
 *
 * If the LCD controller is accessed by the SPI interface we cannot read
 * data directly from the controller. In that case we will read the data from
 * the local framebuffer instead.
 *
 * \param data   Pointer where to store the read data
 * \param page   Page address
 * \param column Offset into page (x coordinate)
 * \param width  Number of bytes to be read
 *
 * The following example will read back the first 128 bytes (first page) from
 * the display memory:
 * \code
 * gfx_mono_ssd1306_get_page(read_buffer, 0, 0, 128);
 * \endcode
 */
void gfx_mono_ssd1306_get_page(gfx_mono_color_t *data, gfx_coord_t page,
		gfx_coord_t column, gfx_coord_t width)
{
#ifdef CONFIG_SSD1306_FRAMEBUFFER
	gfx_mono_framebuffer_get_page(data, page, column, width);
#else
	ssd1306_set_page_address(page);
	ssd1306_set_column_address(column);

	do {
		*data++ = ssd1306_read_data();
	} while (--width);
#endif
}
Пример #8
0
/**
 * \brief Put a byte to the display controller RAM
 *
 * If the LCD controller is accessed by the SPI interface we will also put the
 * data to the local framebuffer.
 *
 * \param page Page address
 * \param column Page offset (x coordinate)
 * \param data Data to be written
 *
 * This example will put the value 0xFF to the first byte in the display memory
 * setting a 8 pixel high column of pixels in the upper left corner of the
 * display.
 * \code
 * gfx_mono_ssd1306_put_byte(0, 0, 0xFF, false);
 * \endcode
 */
void gfx_mono_ssd1306_put_byte(gfx_coord_t page, gfx_coord_t column,
		uint8_t data, bool force)
{
#ifdef CONFIG_SSD1306_FRAMEBUFFER
	if (!force && data == gfx_mono_framebuffer_get_byte(page, column)) {
		return;
	}
	gfx_mono_framebuffer_put_byte(page, column, data);
#endif

	ssd1306_set_page_address(page);
	ssd1306_set_column_address(column);

	ssd1306_write_data(data);
}
Пример #9
0
int main(void)
{
	//! the page address to write to
	uint8_t page_address;
	//! the column address, or the X pixel.
	uint8_t column_address;
	//! store the LCD controller start draw line
	uint8_t start_line_address = 0;

	board_init();
	sysclk_init();

	// Initialize SPI and SSD1306 controller
	ssd1306_init();

	// set addresses at beginning of display
	ssd1306_set_page_address(0);
	ssd1306_set_column_address(0);

	// fill display with lines
	for (page_address = 0; page_address <= 7; page_address++) {
		ssd1306_set_page_address(page_address);
		for (column_address = 0; column_address < 128; column_address++) {
			ssd1306_set_column_address(column_address);
			/* fill every other pixel in the display. This will produce
			horizontal lines on the display. */
			ssd1306_write_data(0x6F);
		}
	}

	// scroll the display using hardware support in the LCD controller
	while (true) {
		ssd1306_set_display_start_line_address(start_line_address++);
		delay_ms(250);
	}
}
Пример #10
0
PROCESS_THREAD(blink_process, ev, data)
{

  static struct etimer et_blink;
  etimer_set(&et_blink, CLOCK_SECOND);
  PROCESS_BEGIN();
static char lux_value[6];
static char lux_value2[6];
static char raw_value[6];
static char raw_value2[6];
static  char temperature_val[6];
static  uint16_t  adc_data=0;
static  uint16_t  adc_data2=0;
static  float adc_lux=0;
static  float adc_lux2=0;
static  float measured_temp=0;
//  static int blinks = 0;

  ssd1306_clear(); 
  ssd1306_set_page_address(0);
  ssd1306_set_column_address(2);
  ssd1306_write_text("Lumen in Lux:");
   
  ssd1306_set_page_address(1);
  ssd1306_set_column_address(2);
  ssd1306_write_text("Raw ADC out :");
 
  ssd1306_set_page_address(2);
  ssd1306_set_column_address(2);
  ssd1306_write_text("Ambient Temperature measured:");


  while(1) {

    PROCESS_WAIT_EVENT();
if (ev==PROCESS_EVENT_TIMER)
   {
   DDRB |=(1<<PORTB4);
   PORTB ^= (1<<PORTB4);
   adc_init();
   adc_data=get_adc(0);
   adc_lux=adc_data*0.9765625;
     
 /*
   amps=adc_volt/10000.0;
   microamps=amps/1000000;
   lux_data=microamps*2;
*/
  itoa(adc_lux, lux_value, 10);
  ssd1306_set_page_address(0);
  ssd1306_set_column_address(73);
  ssd1306_write_text(lux_value);

  itoa(adc_data, raw_value, 10);
  ssd1306_set_page_address(1);
  ssd1306_set_column_address(73);
  ssd1306_write_text(raw_value);

  adc_init_full(ADC_CHAN_ADC0, ADC_TRIG_FREE_RUN, ADC_REF_AVCC, ADC_PS_64);
  adc_conversion_start();
 
  adc_lux2=adc_data2*0.9765626;

  itoa(adc_lux2, lux_value2, 10);
  ssd1306_set_page_address(0);
  ssd1306_set_column_address(95);
  ssd1306_write_text(lux_value2);

  itoa(adc_data2, raw_value2, 10);
  ssd1306_set_page_address(1);
  ssd1306_set_column_address(95);
  ssd1306_write_text(raw_value2);

  measured_temp=ReadTempVal();
  itoa(measured_temp, temperature_val, 10);
  ssd1306_set_page_address(2);
  ssd1306_set_column_address(95);
  ssd1306_write_text(temperature_val);

  }


  }

  PROCESS_END();
}
Пример #11
0
void lcd_line_print(int line, char *str){
	ssd1306_clear();
	ssd1306_set_page_address(line);
	ssd1306_set_column_address(0);
	ssd1306_write_text(str);
}
Пример #12
0
/**
 * \brief The main application.
 */
int main(void)
{
	uint8_t i;
	uint8_t temperature[BUFFER_SIZE];
	uint8_t light[BUFFER_SIZE];
	char value_disp[5];
	uint32_t adc_value;
	uint32_t light_value;
	double temp;

	/* Initialize clocks. */
	sysclk_init();

	/* Initialize GPIO states. */
	board_init();

	/* Configure ADC for light sensor. */
	configure_adc();

	/* Initialize at30tse. */
	at30tse_init();

	/* Configure IO1 buttons. */
	configure_buttons();

	/* Initialize SPI and SSD1306 controller. */
	ssd1306_init();
	ssd1306_clear();

	/* Clear internal buffers. */
	for (i = 0; i < BUFFER_SIZE; ++i) {
		temperature[i] = 0;
		light[i] = 0;
	}

	/* Show the start info. */
	multi_language_show_start_info();

	/* Wait 3 seconds to show the above message. */
	delay_s(3);

	/* Check for valid firmware in SD card. */
	check_valid_firmware();

	while (true) {
		/* Set the trigger and jump to bootloader */
		if (reset_flag) {
			jump_to_bootloader();
		}

		/* Refresh page title only if necessary. */
		if (app_mode_switch > 0) {
			app_mode = (app_mode + 1) % 3;

			/* Clear screen. */
			ssd1306_clear();
			ssd1306_set_page_address(0);
			ssd1306_set_column_address(0);

			if (app_mode == 0) {
				/* Temperature mode. */
				ioport_set_pin_level(OLED1_LED1_PIN, OLED1_LED1_ACTIVE);
				ioport_set_pin_level(OLED1_LED2_PIN, !OLED1_LED2_ACTIVE);
				ioport_set_pin_level(OLED1_LED3_PIN, !OLED1_LED3_ACTIVE);
				multi_language_show_temperature_info();
			} else if (app_mode == 1) {
				/* Light mode. */
				ioport_set_pin_level(OLED1_LED2_PIN, OLED1_LED2_ACTIVE);
				ioport_set_pin_level(OLED1_LED1_PIN, !OLED1_LED1_ACTIVE);
				ioport_set_pin_level(OLED1_LED3_PIN, !OLED1_LED3_ACTIVE);
				multi_language_show_light_info();
			} else {
				/* SD mode. */
				ioport_set_pin_level(OLED1_LED3_PIN, OLED1_LED3_ACTIVE);
				ioport_set_pin_level(OLED1_LED1_PIN, !OLED1_LED1_ACTIVE);
				ioport_set_pin_level(OLED1_LED2_PIN, !OLED1_LED2_ACTIVE);

				sd_listing_pos = 0;
				/* Show SD card info. */
				display_sd_info();
			}

			app_mode_switch = 0;
		}

		/* Shift graph buffers. */
		for (i = 0; i < (BUFFER_SIZE - 1); ++i) {
			temperature[i] = temperature[i + 1];
			light[i] = light[i + 1];
		}

		/* Get temperature. */
		if (at30tse_read_temperature(&temp) == TWI_SUCCESS) {
			/* Don't care about negative temperature. */
			if (temp < 0) {
				temp = 0;
			}

			/* Update temperature for display. */
			/* Note: rescale to 0~24 for better rendering. */
			if (temp > 40) {
				temperature[BUFFER_SIZE - 1] = 24;
			} else {
				temperature[BUFFER_SIZE - 1] = (uint8_t)temp * 24 / 40;
			}
		} else {
			/* Error print zero values. */
			temperature[BUFFER_SIZE - 1] = 0;
		}

		/* Get light sensor information. */
		/* Rescale to 0~24 for better rendering. */
		adc_start_software_conversion(ADC);
		adc_value = adc_channel_get_value(ADC, ADC_CHANNEL_0);
		light[BUFFER_SIZE - 1] = 24 - adc_value * 24 / 1024;

		if (app_mode == 0) {
			/* Display temperature in text format. */
			sprintf(value_disp, "%d", (uint8_t)temp);
			ssd1306_set_column_address(98);
			ssd1306_write_command(SSD1306_CMD_SET_PAGE_START_ADDRESS(0));
			ssd1306_write_text(" ");
			/* Avoid character overlapping. */
			if (temp < 10) {
				ssd1306_clear_char();
			}

			ssd1306_write_text(value_disp);
			/* Display degree symbol. */
			ssd1306_write_data(0x06);
			ssd1306_write_data(0x06);
			ssd1306_write_text("c");

			/* Refresh graph. */
			ssd1306_draw_graph(0, 2, BUFFER_SIZE, 2, temperature);
		} else if (app_mode == 1) {
			light_value = 100 - (adc_value * 100 / 1024);
			sprintf(value_disp, "%lu", light_value);
			ssd1306_set_column_address(98);
			ssd1306_write_command(SSD1306_CMD_SET_PAGE_START_ADDRESS(0));
			ssd1306_write_text(" ");
			/* Avoid character overlapping. */
			if (light_value < 10) {
				ssd1306_clear_char();
			}

			ssd1306_write_text(value_disp);
			ssd1306_write_text("%");
			/* Avoid character overlapping. */
			if (light_value < 100) {
				ssd1306_clear_char();
			}

			/* Refresh graph. */
			ssd1306_draw_graph(0, 2, BUFFER_SIZE, 2, light);
		} else {
			/**
			 * Refresh screen if card was inserted/removed or
			 * browsing content.
			 */
			if (sd_update == 1) {
				/* Clear screen. */
				ssd1306_clear();
				ssd1306_set_page_address(0);
				ssd1306_set_column_address(0);

				if (sd_listing_pos == 0) {
					/* Show SD card info. */
					display_sd_info();
				} else {
					/* List SD card files. */
					display_sd_files_unicode();
				}

				sd_update = 0;
			}
		}

		/* Wait and stop screen flickers. */
		delay_ms(150);

		if (app_mode_switch == 0) {
			pio_enable_interrupt(OLED1_PIN_PUSHBUTTON_1_PIO,
					OLED1_PIN_PUSHBUTTON_1_MASK);
		}
		if (sd_update == 0) {
			pio_enable_interrupt(OLED1_PIN_PUSHBUTTON_2_PIO,
					OLED1_PIN_PUSHBUTTON_2_MASK);
			pio_enable_interrupt(OLED1_PIN_PUSHBUTTON_3_PIO,
					OLED1_PIN_PUSHBUTTON_3_MASK);
		}

	}
}
Пример #13
0
int main(void)
{
	uint8_t i;
	uint8_t temperature[BUFFER_SIZE];
	uint8_t light[BUFFER_SIZE];
	uint8_t value_disp[5];
	uint32_t adc_value;
	double temp;

	// Initialize clocks.
	sysclk_init();

	// Initialize GPIO states.
	board_init();

	// Configure ADC for light sensor.
	configure_adc();

	// Initialize at30tse.
	at30tse_init();

	// Configure IO1 buttons.
	configure_buttons();

	// Initialize SPI and SSD1306 controller.
	ssd1306_init();
	ssd1306_clear();

	// Clear internal buffers.
	for (i = 0; i < BUFFER_SIZE; ++i)
	{
		temperature[i] = 0;
		light[i] = 0;
	}

	while (true)
	{
		/* Refresh page title only if necessary. */
		if (app_mode_switch > 0)
		{
			app_mode = app_mode_switch - 1;

			// Clear screen.
			ssd1306_clear();
			ssd1306_set_page_address(0);
			ssd1306_set_column_address(0);

			/* Temperature mode. */
			if (app_mode == 0)
			{
				ioport_set_pin_level(IO1_LED1_PIN, IO1_LED1_ACTIVE);
				ioport_set_pin_level(IO1_LED2_PIN, !IO1_LED2_ACTIVE);
				ioport_set_pin_level(IO1_LED3_PIN, !IO1_LED3_ACTIVE);
				ssd1306_write_text("Temperature sensor:");
			}
			/* Light mode. */
			else if (app_mode == 1)
			{
				ioport_set_pin_level(IO1_LED2_PIN, IO1_LED2_ACTIVE);
				ioport_set_pin_level(IO1_LED1_PIN, !IO1_LED1_ACTIVE);
				ioport_set_pin_level(IO1_LED3_PIN, !IO1_LED3_ACTIVE);
				ssd1306_write_text("Light sensor:");
			}
			/* SD mode. */
			else
			{
				ioport_set_pin_level(IO1_LED3_PIN, IO1_LED3_ACTIVE);
				ioport_set_pin_level(IO1_LED1_PIN, !IO1_LED1_ACTIVE);
				ioport_set_pin_level(IO1_LED2_PIN, !IO1_LED2_ACTIVE);

				display_sd_info();
			}
			app_mode_switch = 0;
		}

		// Shift graph buffers.
		for (i = 0; i < BUFFER_SIZE - 1; ++i)
		{
			temperature[i] = temperature[i + 1];
			light[i] = light[i + 1];
		}

		// Get temperature in a range from 0 to 40 degrees.
		if (at30tse_read_temperature(&temp) == TWI_SUCCESS)
		{
			// Don't care about negative temperature.
			if (temp < 0)
				temp = 0;

			// Update temperature for display.
			// Note: -12 in order to rescale for better rendering.
			if (temp < 12)
				temperature[BUFFER_SIZE - 1] = 0;
			else
				temperature[BUFFER_SIZE - 1] = temp - 12;
		}
		else
		{
			// Error print zero values.
			temperature[BUFFER_SIZE - 1] = 0;
		}

		// Get light sensor information.
		// Rescale for better rendering.
		adc_start(ADC);
		adc_value = adc_get_channel_value(ADC, ADC_CHANNEL_4);
		light[BUFFER_SIZE - 1] = 24 - adc_value * 24 / 4096;

		// Print temperature in text format.
		if (app_mode == 0)
		{
			sprintf(value_disp, "%d", (uint8_t)temp);
			ssd1306_set_column_address(95);
			ssd1306_write_command(SSD1306_CMD_SET_PAGE_START_ADDRESS(0));
			ssd1306_write_text(" ");
			ssd1306_write_text(value_disp);
			// Display degree symbol.
			ssd1306_write_data(0x06);
			ssd1306_write_data(0x06);
			ssd1306_write_text("c");

			// Refresh graph.
			ssd1306_draw_graph(0, 1, BUFFER_SIZE, 3, temperature);
		}
		else if (app_mode == 1)
		{
			sprintf(value_disp, "%lu", 100 - (adc_value * 100 / 4096));
			ssd1306_set_column_address(98);
			ssd1306_write_command(SSD1306_CMD_SET_PAGE_START_ADDRESS(0));
			ssd1306_write_text(" ");
			ssd1306_write_text(value_disp);
			ssd1306_write_text("%");

			// Refresh graph.
			ssd1306_draw_graph(0, 1, BUFFER_SIZE, 3, light);
		}
		else
		{
			// Is card has been inserted or removed?
			if (sd_status_update == 1)
			{
				// Clear screen.
				ssd1306_clear();
				ssd1306_set_page_address(0);
				ssd1306_set_column_address(0);

				// Show SD card info.
				display_sd_info();

				sd_status_update = 0;
			}

		}

		/* Wait and stop screen flickers. */
		delay_ms(50);
	}
}
Пример #14
0
/**
 * \brief Show SD card status on the OLED screen.
 */
static void display_sd_info(void)
{
	uint8_t card_check;
	uint8_t sd_card_type;
	uint8_t sd_card_version;
	uint32_t sd_card_size;
	uint8_t size[10];

	// Is SD card present?
	if (gpio_pin_is_low(SD_MMC_0_CD_GPIO) == false)
	{
		ssd1306_write_text("Please insert SD card...");
	}
	else
	{
		ssd1306_write_text("SD card information:");

		sd_mmc_init();
		card_check = sd_mmc_check(0);
		while (card_check != SD_MMC_OK)
		{
			card_check = sd_mmc_check(0);
			delay_ms(1);
		}

		if (card_check == SD_MMC_OK)
		{
			sd_card_type = sd_mmc_get_type(0);
			sd_card_version = sd_mmc_get_version(0);
			sd_card_size = sd_mmc_get_capacity(0);

			ssd1306_set_page_address(1);
			ssd1306_set_column_address(0);

			// Card type
			switch(sd_card_type)
			{
				case CARD_TYPE_SD:
				ssd1306_write_text("- Type: Normal SD card");
				break;
				case CARD_TYPE_SDIO:
				ssd1306_write_text("- Type: SDIO card");
				break;
				case CARD_TYPE_HC:
				ssd1306_write_text("- Type: High Capacity card");
				break;
				case CARD_TYPE_SD_COMBO:
				ssd1306_write_text("- Type: SDIO/Memory card");
				break;
				default:
				ssd1306_write_text("- Type: unknown");
			}

			ssd1306_set_page_address(2);
			ssd1306_set_column_address(0);

			// SD card version
			switch(sd_card_version)
			{
				case CARD_VER_SD_1_0:
				ssd1306_write_text("- Version: 1.0x");
				break;
				case CARD_VER_SD_1_10:
				ssd1306_write_text("- Version: 1.10");
				break;
				case CARD_VER_SD_2_0:
				ssd1306_write_text("- Version: 2.00");
				break;
				case CARD_VER_SD_3_0:
				ssd1306_write_text("- Version: 3.0x");
				break;
				default:
				ssd1306_write_text("- Version: unknown");
			}

			ssd1306_set_page_address(3);
			ssd1306_set_column_address(0);

			sprintf(size, "- Total size: %lu KB", sd_card_size);
			ssd1306_write_text(size);
		}
	}
}