Merge branch 'contiki'
Conflicts: cpu/cc26xx-cc13xx/lib/cc13xxware cpu/cc26xx-cc13xx/lib/cc26xxware
This commit is contained in:
commit
2f8549aaae
319 changed files with 58114 additions and 6745 deletions
26
dev/bme280/README.bme280
Normal file
26
dev/bme280/README.bme280
Normal file
|
@ -0,0 +1,26 @@
|
|||
|
||||
Contiki implementation for Bosch Sensortec BME280 sensor.
|
||||
BME280 is compact and fast and includes temp, RH, and pressure.
|
||||
Chip uses I2C or SPI. This implementation and follow Contiki
|
||||
device API and I2C.
|
||||
|
||||
For better performance and less chip warm up and less I2C transactions
|
||||
burst read is recommended. Here all T/RH/P is read in one single
|
||||
I2C read and kept the measurements have the same time.
|
||||
|
||||
The burst read is stored in struct bme280_mea which accessible from
|
||||
the Contiki. Also note that the full chip resolution is available.
|
||||
The variables are overscaled to give the app full controlover resolution.
|
||||
|
||||
See bme280.h
|
||||
|
||||
The pressure can be calculated with 32 or 64. The define BME280_64BIT
|
||||
controls this. Typically in your project-conf.h
|
||||
|
||||
Implemented according to datasheet Rev 1.1.
|
||||
|
||||
Limitations:
|
||||
Implementation implements Weather Mode which uses forced one-shot
|
||||
mode no oversampling nor filters and reads all T/RH/P in one read.
|
||||
|
||||
|
45
dev/bme280/bme280-arch.h
Normal file
45
dev/bme280/bme280-arch.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Zolertia <http://www.zolertia.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#ifndef BME280_ARCH_H
|
||||
#define BME280_ARCH_H
|
||||
|
||||
/* Initialize the I2C module */
|
||||
void bme280_arch_i2c_init();
|
||||
|
||||
/* I2C read registers */
|
||||
void bme280_arch_i2c_read_mem(uint8_t addr, uint8_t reg, uint8_t *buf,
|
||||
uint8_t bytes);
|
||||
|
||||
/* I2C write to a single register */
|
||||
void bme280_arch_i2c_write_mem(uint8_t addr, uint8_t reg, uint8_t value);
|
||||
|
||||
#endif
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @} */
|
79
dev/bme280/bme280-sensor.c
Normal file
79
dev/bme280/bme280-sensor.c
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Copyright Robert Olsson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*
|
||||
*
|
||||
* Author : Robert Olsson rolss@kth.se/robert@radio-sensors.com
|
||||
* Created : 2016-09-14
|
||||
*/
|
||||
|
||||
#include "contiki.h"
|
||||
#include "lib/sensors.h"
|
||||
#include "dev/bme280/bme280.h"
|
||||
#include "dev/bme280/bme280-sensor.h"
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int
|
||||
value(int type)
|
||||
{
|
||||
/* Read all measurements with one burst read */
|
||||
bme280_read(BME280_MODE_WEATHER);
|
||||
|
||||
/* Return a la Contiki API */
|
||||
switch(type) {
|
||||
|
||||
case BME280_SENSOR_TEMP:
|
||||
return bme280_mea.t_overscale100 / 100;
|
||||
|
||||
case BME280_SENSOR_HUMIDITY:
|
||||
return bme280_mea.h_overscale1024 >> 10;
|
||||
|
||||
case BME280_SENSOR_PRESSURE:
|
||||
/* Scale down w. 10 not to overslow the signed int */
|
||||
#ifdef BME280_64BIT
|
||||
return bme280_mea.p_overscale256 / (256 * 10);
|
||||
#else
|
||||
return bme280_mea.p / 10;
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int
|
||||
status(int type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int
|
||||
configure(int type, int c)
|
||||
{
|
||||
return bme280_init(BME280_MODE_WEATHER);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
SENSORS_SENSOR(bme280_sensor, "bme280", value, configure, status);
|
48
dev/bme280/bme280-sensor.h
Normal file
48
dev/bme280/bme280-sensor.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Copyright Robert Olsson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*
|
||||
*
|
||||
* Author : Robert Olsson rolss@kth.se/robert@radio-sensors.com
|
||||
* Created : 2016-09-14
|
||||
*/
|
||||
|
||||
#ifndef BME280_SENSOR_H_
|
||||
#define BME280_SENSOR_H_
|
||||
|
||||
#include "lib/sensors.h"
|
||||
#include "bme280.h"
|
||||
|
||||
extern const struct sensors_sensor bme280_sensor;
|
||||
|
||||
#define BME280_SENSOR_TEMP 0
|
||||
#define BME280_SENSOR_HUMIDITY 1
|
||||
#define BME280_SENSOR_PRESSURE 2
|
||||
|
||||
#endif /* BME280_SENSOR_H_ */
|
276
dev/bme280/bme280.c
Normal file
276
dev/bme280/bme280.c
Normal file
|
@ -0,0 +1,276 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Copyright Robert Olsson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*
|
||||
*
|
||||
* Author : Robert Olsson rolss@kth.se/robert@radio-sensors.com
|
||||
* Created : 2016-09-14
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Basic functions for Bosch BME280 based on datasheet Rev 1.1
|
||||
*/
|
||||
|
||||
#include "contiki.h"
|
||||
#include <string.h>
|
||||
#include "bme280.h"
|
||||
#include "bme280-arch.h"
|
||||
#include "lib/sensors.h"
|
||||
|
||||
static struct {
|
||||
unsigned short dig_t1;
|
||||
signed short dig_t2;
|
||||
signed short dig_t3;
|
||||
unsigned short dig_p1;
|
||||
signed short dig_p2;
|
||||
signed short dig_p3;
|
||||
signed short dig_p4;
|
||||
signed short dig_p5;
|
||||
signed short dig_p6;
|
||||
signed short dig_p7;
|
||||
signed short dig_p8;
|
||||
signed short dig_p9;
|
||||
unsigned char dig_h1;
|
||||
signed short dig_h2;
|
||||
unsigned char dig_h3;
|
||||
signed short dig_h4;
|
||||
signed short dig_h5;
|
||||
signed char dig_h6;
|
||||
int32_t t_fine;
|
||||
uint8_t mode;
|
||||
} bm;
|
||||
|
||||
int32_t
|
||||
bme280_t_overscale100(int32_t ut)
|
||||
{
|
||||
int32_t v1, v2, t;
|
||||
|
||||
v1 = ((((ut >> 3) - ((int32_t)bm.dig_t1 << 1))) *
|
||||
((int32_t)bm.dig_t2)) >> 11;
|
||||
|
||||
v2 = (((((ut >> 4) - ((int32_t)bm.dig_t1)) * ((ut >> 4) -
|
||||
((int32_t)bm.dig_t1))) >> 12) * ((int32_t)bm.dig_t3)) >> 14;
|
||||
|
||||
bm.t_fine = v1 + v2;
|
||||
t = (bm.t_fine * 5 + 128) >> 8;
|
||||
return t;
|
||||
}
|
||||
#ifdef BME280_32BIT
|
||||
static uint32_t
|
||||
bme280_p(int32_t up)
|
||||
{
|
||||
int32_t v1, v2;
|
||||
uint32_t p;
|
||||
|
||||
v1 = (((int32_t)bm.t_fine) >> 1) - (int32_t)64000;
|
||||
v2 = (((v1 >> 2) * (v1 >> 2)) >> 11) * ((int32_t)bm.dig_p6);
|
||||
v2 = v2 + ((v1 * ((int32_t)bm.dig_p5)) << 1);
|
||||
v2 = (v2 >> 2) + (((int32_t)bm.dig_p4) << 16);
|
||||
|
||||
v1 = (((bm.dig_p3 * (((v1 >> 2) * (v1 >> 2)) >> 13)) >> 3) +
|
||||
((((int32_t)bm.dig_p2) * v1) >> 1)) >> 18;
|
||||
|
||||
v1 = ((((32768 + v1)) * ((int32_t)bm.dig_p1)) >> 15);
|
||||
|
||||
if(v1 == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
p = (((uint32_t)(((int32_t)1048576) - up) - (v2 >> 12))) * 3125;
|
||||
|
||||
if(p < 0x80000000) {
|
||||
p = (p << 1) / ((uint32_t)v1);
|
||||
} else {
|
||||
p = (p / (uint32_t)v1) * 2;
|
||||
}
|
||||
|
||||
v1 = (((int32_t)bm.dig_p9) * ((int32_t)(((p >> 3) * (p >> 3)) >> 13))) >> 12;
|
||||
v2 = (((int32_t)(p >> 2)) * ((int32_t)bm.dig_p8)) >> 13;
|
||||
p = (uint32_t)((int32_t)p + ((v1 + v2 + bm.dig_p7) >> 4));
|
||||
return p;
|
||||
}
|
||||
#else
|
||||
|
||||
static uint32_t
|
||||
bme280_p_overscale256(int32_t up)
|
||||
{
|
||||
int64_t v1, v2, p;
|
||||
|
||||
v1 = ((int64_t)bm.t_fine) - 128000;
|
||||
v2 = v1 * v1 * (int64_t)bm.dig_p6;
|
||||
v2 = v2 + ((v1 * (int64_t)bm.dig_p5) << 17);
|
||||
v2 = v2 + (((int64_t)bm.dig_p4) << 35);
|
||||
v1 = ((v1 * v1 * (int64_t)bm.dig_p3) >> 8) + ((v1 * (int64_t)bm.dig_p2) << 12);
|
||||
v1 = (((((int64_t)1) << 47) + v1)) * ((int64_t)bm.dig_p1) >> 33;
|
||||
|
||||
if(v1 == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
p = 1048576 - up;
|
||||
p = (((p << 31) - v2) * 3125) / v1;
|
||||
v1 = (((int64_t)bm.dig_p9) * (p >> 13) * (p >> 13)) >> 25;
|
||||
v2 = (((int64_t)bm.dig_p8) * p) >> 19;
|
||||
p = (((p + v1 + v2) >> 8) + (((int64_t)bm.dig_p7) << 4));
|
||||
return (uint32_t)p;
|
||||
}
|
||||
#endif
|
||||
|
||||
static uint32_t
|
||||
bme280_h_overscale1024(int32_t uh)
|
||||
{
|
||||
int32_t v1;
|
||||
v1 = (bm.t_fine - ((int32_t)76800));
|
||||
v1 = (((((uh << 14) - (((int32_t)bm.dig_h4) << 20) - (((int32_t)bm.dig_h5) * v1)) + ((int32_t)16384)) >> 15)
|
||||
* (((((((v1 * ((int32_t)bm.dig_h6)) >> 10) * (((v1 * ((int32_t)bm.dig_h3)) >> 11) + ((int32_t)32768)))
|
||||
>> 10) + ((int32_t)2097152)) * ((int32_t)bm.dig_h2) + 8192) >> 14));
|
||||
v1 = (v1 - (((((v1 >> 15) * (v1 >> 15)) >> 7) * ((int32_t)bm.dig_h1)) >> 4));
|
||||
v1 = (v1 < 0 ? 0 : v1);
|
||||
v1 = (v1 > 419430400 ? 419430400 : v1);
|
||||
return (uint32_t)(v1 >> 12);
|
||||
}
|
||||
uint8_t
|
||||
bme280_init(uint8_t mode)
|
||||
{
|
||||
uint16_t i;
|
||||
uint8_t buf[26];
|
||||
|
||||
bme280_arch_i2c_init();
|
||||
|
||||
/* Do not mess with other chips */
|
||||
bme280_arch_i2c_read_mem(BME280_ADDR, 0xD0, buf, 1);
|
||||
if(buf[0] != BME280_CHIP_ID) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bme280_arch_i2c_write_mem(BME280_ADDR, BME280_CNTL_RESET, 0xB6);
|
||||
|
||||
for(i = 0; i < BME280_MAX_WAIT; i++) {
|
||||
clock_delay_usec(1000);
|
||||
}
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
/* Burst read of all calibration part 1 */
|
||||
bme280_arch_i2c_read_mem(BME280_ADDR, BME280_DIG_T1_ADDR, buf, sizeof(buf));
|
||||
bm.dig_t1 = ((uint16_t)buf[1] << 8) | (uint16_t)buf[0];
|
||||
bm.dig_t2 = ((int16_t)buf[3] << 8) | (uint16_t)buf[2];
|
||||
bm.dig_t3 = ((int16_t)buf[5] << 8) | (uint16_t)buf[4];
|
||||
bm.dig_p1 = ((uint16_t)buf[7] << 8) | (uint16_t)buf[6];
|
||||
bm.dig_p2 = ((int16_t)buf[9] << 8) | (uint16_t)buf[8];
|
||||
bm.dig_p3 = ((int16_t)buf[11] << 8) | (uint16_t)buf[10];
|
||||
bm.dig_p4 = ((int16_t)buf[13] << 8) | (uint16_t)buf[12];
|
||||
bm.dig_p5 = ((int16_t)buf[15] << 8) | (uint16_t)buf[14];
|
||||
bm.dig_p6 = ((int16_t)buf[17] << 8) | (uint16_t)buf[16];
|
||||
bm.dig_p7 = ((int16_t)buf[19] << 8) | (uint16_t)buf[18];
|
||||
bm.dig_p8 = ((int16_t)buf[21] << 8) | (uint16_t)buf[20];
|
||||
bm.dig_p9 = ((int16_t)buf[23] << 8) | (uint16_t)buf[22];
|
||||
/* A0 not used */
|
||||
bm.dig_h1 = (unsigned char)buf[25];
|
||||
|
||||
/* Burst read of all calibration part 2 */
|
||||
bme280_arch_i2c_read_mem(BME280_ADDR, BME280_DIG_H2_ADDR, buf, 8);
|
||||
bm.dig_h2 = ((int16_t)buf[1] << 8) | (uint16_t)buf[0];
|
||||
bm.dig_h3 = (unsigned char)buf[2];
|
||||
bm.dig_h4 = ((int16_t)buf[3] << 4) | (((uint16_t)buf[4]) & 0xF);
|
||||
bm.dig_h5 = ((int16_t)buf[6] << 4) | (((uint16_t)buf[5]) & 0xF);
|
||||
bm.dig_h6 = (unsigned char)buf[7];
|
||||
|
||||
bm.mode = mode;
|
||||
return 1;
|
||||
}
|
||||
void
|
||||
bme280_read(uint8_t mode)
|
||||
{
|
||||
int32_t ut, uh, up;
|
||||
uint8_t buf[8], sleep;
|
||||
uint16_t i;
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
/* Are we initilized and in the right mode? */
|
||||
if(mode == BME280_MODE_NONE || mode != bm.mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
ut = uh = up = 0;
|
||||
|
||||
/* Weather mode. See sectiom 3.5 Datasheet */
|
||||
if(mode == BME280_MODE_WEATHER) {
|
||||
/* Humidity oversampling *1 */
|
||||
bme280_arch_i2c_write_mem(BME280_ADDR, BME280_CNTL_HUM, 0x01);
|
||||
|
||||
/* 00100111 0x27 oversampling *1 for t and p plus normal mode */
|
||||
/* 0.5 ms -- no filter -- no SPI */
|
||||
bme280_arch_i2c_write_mem(BME280_ADDR, BME280_CONTROL, 0x00);
|
||||
|
||||
/* 00100110 0x26 oversampling *1 for t and p plus forced mode */
|
||||
/* Trigger measurement needed for every time in forced mode */
|
||||
bme280_arch_i2c_write_mem(BME280_ADDR, BME280_CNTL_MEAS, 0x26);
|
||||
/* Wait to get into sleep mode == measurement done */
|
||||
for(i = 0; i < BME280_MAX_WAIT; i++) {
|
||||
bme280_arch_i2c_read_mem(BME280_ADDR, BME280_CNTL_MEAS, &sleep, 1);
|
||||
sleep = sleep& 0x03;
|
||||
if(sleep== 0) {
|
||||
break;
|
||||
} else {
|
||||
clock_delay_usec(1000);
|
||||
}
|
||||
}
|
||||
if(i == BME280_MAX_WAIT) {
|
||||
return; /* error wait*/
|
||||
}
|
||||
} else { /* if(mode == BME280_MODE_WEATHER) */
|
||||
return; /* error mode*/
|
||||
}
|
||||
|
||||
/* Burst read of all measurements */
|
||||
bme280_arch_i2c_read_mem(BME280_ADDR, BME280_PRESS, buf, 8);
|
||||
ut = (uint32_t)(buf[3]) << 12 | (uint32_t)(buf[4]) << 4 | (uint32_t)buf[5] >> 4;
|
||||
up = (uint32_t)(buf[0]) << 12 | (uint32_t)(buf[1]) << 4 | (uint32_t)buf[2] >> 4;
|
||||
uh = (uint32_t)(buf[6]) << 8 | (uint32_t)buf[7];
|
||||
|
||||
bme280_mea.t_overscale100 = bme280_t_overscale100(ut);
|
||||
bme280_mea.h_overscale1024 = bme280_h_overscale1024(uh);
|
||||
#ifdef BME280_64BIT
|
||||
bme280_mea.p_overscale256 = bme280_p_overscale256(up);
|
||||
#else
|
||||
bme280_mea.p = bme280_p(up);
|
||||
#endif
|
||||
|
||||
#if TEST
|
||||
printf("T_BME280=%5.2f", (double)bme280_mea.t_overscale100 / 100.);
|
||||
printf(" RH_BME280=%5.2f ", (double)bme280_mea.h_overscale1024 / 1024.);
|
||||
#ifdef BME280_64BIT
|
||||
printf(" P_BME280=%5.2f\n", (double)bme280_mea.p_overscale256 / 256.);
|
||||
#else
|
||||
printf(" P_BME280=%5.2f\n", (double)bme280_mea.p);
|
||||
#endif
|
||||
#endif
|
||||
}
|
110
dev/bme280/bme280.h
Normal file
110
dev/bme280/bme280.h
Normal file
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Copyright Robert Olsson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*
|
||||
*
|
||||
* Author : Robert Olsson rolss@kth.se/robert@radio-sensors.com
|
||||
*
|
||||
* Created : 2016-09-14
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Definitions for the Bosch BME280 based on datasheet Rev 1.1
|
||||
*/
|
||||
|
||||
#ifndef BME280_H
|
||||
#define BME280_H
|
||||
|
||||
#ifndef BME280_32BIT
|
||||
#define BME280_64BIT
|
||||
#endif
|
||||
|
||||
uint8_t bme280_init(uint8_t mode);
|
||||
void bme280_read(uint8_t mode);
|
||||
|
||||
#ifdef BME280_CONF_ADDR
|
||||
#define BME280_ADDR BME280_CONF_ADDR
|
||||
#else
|
||||
#define BME280_ADDR (0x77 << 1) /* Alternative 0x76 */
|
||||
#endif
|
||||
|
||||
/* Diffrent BOSCH chip id's */
|
||||
#define BMP085_CHIP_ID 0x55 /* And also BMP180 */
|
||||
#define BMP280_CHIP_ID 0x58
|
||||
#define BME280_CHIP_ID 0x60
|
||||
|
||||
/* Address map */
|
||||
#define BME280_DIG_T1_ADDR 0x88
|
||||
#define BME280_DIG_T2_ADDR 0x8A
|
||||
#define BME280_DIG_T3_ADDR 0x8C
|
||||
#define BME280_DIG_P1_ADDR 0x8E
|
||||
#define BME280_DIG_P2_ADDR 0x90
|
||||
#define BME280_DIG_P3_ADDR 0x92
|
||||
#define BME280_DIG_P4_ADDR 0x94
|
||||
#define BME280_DIG_P5_ADDR 0x96
|
||||
#define BME280_DIG_P6_ADDR 0x98
|
||||
#define BME280_DIG_P7_ADDR 0x9A
|
||||
#define BME280_DIG_P8_ADDR 0x9C
|
||||
#define BME280_DIG_P9_ADDR 0x9E
|
||||
#define BME280_DIG_H1_ADDR 0xA1
|
||||
#define BMP_CHIP_ID_ADDR 0xD0
|
||||
#define BME280_CNTL_RESET 0xE0
|
||||
#define BME280_DIG_H2_ADDR 0xE1
|
||||
#define BME280_DIG_H3_ADDR 0xE3
|
||||
#define BME280_DIG_H4_ADDR 0xE4
|
||||
#define BME280_DIG_H5_ADDR 0xE5
|
||||
#define BME280_DIG_H6_ADDR 0xE7
|
||||
#define BME280_CNTL_HUM 0xF2
|
||||
#define BME280_STATUS 0xF3
|
||||
#define BME280_CNTL_MEAS 0xF4
|
||||
#define BME280_CONTROL 0xF5
|
||||
#define BME280_PRESS 0xF7
|
||||
|
||||
/* Function modes outlined in datasheet */
|
||||
#define BME280_MODE_NONE 0
|
||||
#define BME280_MODE_WEATHER 1
|
||||
#define BME280_MODE_HUMIDITY 2
|
||||
#define BME280_MODE_INDOOR_NAVIGATION 3
|
||||
#define BME280_MODE_GAMING 4
|
||||
|
||||
#define BME280_MAX_WAIT 300 /* ms. Forced mode max wait */
|
||||
|
||||
|
||||
struct {
|
||||
int32_t t_overscale100;
|
||||
uint32_t h_overscale1024;
|
||||
#ifdef BME280_64BIT
|
||||
uint32_t p_overscale256;
|
||||
#else
|
||||
uint32_t p;
|
||||
#endif
|
||||
} bme280_mea;
|
||||
|
||||
#endif /* BME280_H */
|
98
dev/disk/disk.h
Normal file
98
dev/disk/disk.h
Normal file
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Benoît Thébaudeau <benoit@wsystem.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/**
|
||||
* \addtogroup dev
|
||||
* @{
|
||||
*
|
||||
* \defgroup disk Disk device drivers
|
||||
*
|
||||
* Documentation for all the disk device drivers.
|
||||
* @{
|
||||
*
|
||||
* \file
|
||||
* Header file defining the disk device driver API.
|
||||
*/
|
||||
#ifndef DISK_H_
|
||||
#define DISK_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** Disk status flags. */
|
||||
typedef enum {
|
||||
DISK_STATUS_INIT = 0x01, /**< Device initialized and ready to work */
|
||||
DISK_STATUS_DISK = 0x02, /**< Medium present in the drive */
|
||||
DISK_STATUS_WRITABLE = 0x04 /**< Writable medium */
|
||||
} disk_status_t;
|
||||
|
||||
/** Generic disk I/O control commands. */
|
||||
typedef enum {
|
||||
DISK_IOCTL_CTRL_SYNC, /**< Synchronize the cached writes to persistent storage */
|
||||
DISK_IOCTL_GET_SECTOR_COUNT, /**< Get the sector count through the \c uint32_t pointed to by \c buff */
|
||||
DISK_IOCTL_GET_SECTOR_SIZE, /**< Get the sector size through the \c uint16_t pointed to by \c buff */
|
||||
DISK_IOCTL_GET_BLOCK_SIZE, /**< Get the erase block size (in sectors) through the \c uint32_t pointed to by \c buff */
|
||||
DISK_IOCTL_CTRL_TRIM /**< Trim the sector range within the \c uint32_t boundaries pointed to by \c buff */
|
||||
} disk_ioctl_t;
|
||||
|
||||
/** Disk access result codes. */
|
||||
typedef enum {
|
||||
DISK_RESULT_OK, /**< Success */
|
||||
DISK_RESULT_IO_ERROR, /**< Unrecoverable I/O error */
|
||||
DISK_RESULT_WR_PROTECTED, /**< Write-protected medium */
|
||||
DISK_RESULT_NO_INIT, /**< Device not initialized */
|
||||
DISK_RESULT_INVALID_ARG /**< Invalid argument */
|
||||
} disk_result_t;
|
||||
|
||||
/** Disk driver API structure. */
|
||||
struct disk_driver {
|
||||
/** Get device status. */
|
||||
disk_status_t (*status)(uint8_t dev);
|
||||
|
||||
/** Initialize device. */
|
||||
disk_status_t (*initialize)(uint8_t dev);
|
||||
|
||||
/** Read sector(s). */
|
||||
disk_result_t (*read)(uint8_t dev, void *buff, uint32_t sector,
|
||||
uint32_t count);
|
||||
|
||||
/** Write sector(s). */
|
||||
disk_result_t (*write)(uint8_t dev, const void *buff, uint32_t sector,
|
||||
uint32_t count);
|
||||
|
||||
/** Control device-specific features. */
|
||||
disk_result_t (*ioctl)(uint8_t dev, uint8_t cmd, void *buff);
|
||||
};
|
||||
|
||||
#endif /* DISK_H_ */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
98
dev/disk/mmc/mmc-arch.h
Normal file
98
dev/disk/mmc/mmc-arch.h
Normal file
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Benoît Thébaudeau <benoit@wsystem.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/**
|
||||
* \addtogroup mmc
|
||||
* @{
|
||||
*
|
||||
* \defgroup mmc-arch SD/MMC architecture-specific definitions
|
||||
*
|
||||
* SD/MMC device driver architecture-specific definitions.
|
||||
* @{
|
||||
*
|
||||
* \file
|
||||
* Header file for the SD/MMC device driver architecture-specific definitions.
|
||||
*/
|
||||
#ifndef MMC_ARCH_H_
|
||||
#define MMC_ARCH_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/** \brief Callback of the SD/MMC driver to call when the card-detection signal
|
||||
* changes.
|
||||
* \param dev Device
|
||||
* \param cd Whether a card is detected
|
||||
* \note Using this function is not mandatory. This only allows to detect a card
|
||||
* replacement between two successive calls to the SD/MMC driver API.
|
||||
*/
|
||||
void mmc_arch_cd_changed_callback(uint8_t dev, bool cd);
|
||||
|
||||
/** \brief Gets the state of the card-detection signal.
|
||||
* \param dev Device
|
||||
* \return Whether a card is detected
|
||||
*/
|
||||
bool mmc_arch_get_cd(uint8_t dev);
|
||||
|
||||
/** \brief Gets the state of the write-protection signal.
|
||||
* \param dev Device
|
||||
* \return Whether the card is write-protected
|
||||
*/
|
||||
bool mmc_arch_get_wp(uint8_t dev);
|
||||
|
||||
/** \brief Sets the SPI /CS signal as indicated.
|
||||
* \param dev Device
|
||||
* \param sel Whether to assert /CS
|
||||
*/
|
||||
void mmc_arch_spi_select(uint8_t dev, bool sel);
|
||||
|
||||
/** \brief Sets the SPI clock frequency.
|
||||
* \param dev Device
|
||||
* \param freq Frequency (Hz)
|
||||
*/
|
||||
void mmc_arch_spi_set_clock_freq(uint8_t dev, uint32_t freq);
|
||||
|
||||
/** \brief Performs an SPI transfer.
|
||||
* \param dev Device
|
||||
* \param tx_buf Pointer to the transmission buffer, or \c NULL
|
||||
* \param tx_cnt Number of bytes to transmit, or \c 0
|
||||
* \param rx_buf Pointer to the reception buffer, or \c NULL
|
||||
* \param rx_cnt Number of bytes to receive, or \c 0
|
||||
*/
|
||||
void mmc_arch_spi_xfer(uint8_t dev, const void *tx_buf, size_t tx_cnt,
|
||||
void *rx_buf, size_t rx_cnt);
|
||||
|
||||
#endif /* MMC_ARCH_H_ */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
608
dev/disk/mmc/mmc.c
Normal file
608
dev/disk/mmc/mmc.c
Normal file
|
@ -0,0 +1,608 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Benoît Thébaudeau <benoit@wsystem.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Based on the FatFs Module STM32 Sample Project,
|
||||
* Copyright (c) 2014, ChaN
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/**
|
||||
* \addtogroup mmc
|
||||
* @{
|
||||
*
|
||||
* \file
|
||||
* Implementation of the SD/MMC device driver.
|
||||
*/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "contiki.h"
|
||||
#include "sys/clock.h"
|
||||
#include "sys/rtimer.h"
|
||||
#include "dev/watchdog.h"
|
||||
#include "mmc-arch.h"
|
||||
#include "mmc.h"
|
||||
|
||||
/* Data read/write block length */
|
||||
#define BLOCK_LEN 512
|
||||
/*
|
||||
* Logical sector size exposed to the disk API, not to be confused with the SDSC
|
||||
* sector size, which is the size of an erasable sector
|
||||
*/
|
||||
#define SECTOR_SIZE BLOCK_LEN
|
||||
|
||||
/* Clock frequency in card identification mode: fOD <= 400 kHz */
|
||||
#define CLOCK_FREQ_CARD_ID_MODE 400000
|
||||
/*
|
||||
* Clock frequency in data transfer mode: fPP <= 20 MHz, limited by the
|
||||
* backward-compatible MMC interface timings
|
||||
*/
|
||||
#define CLOCK_FREQ_DATA_XFER_MODE 20000000
|
||||
|
||||
/* SPI-mode command list */
|
||||
#define CMD0 0 /* GO_IDLE_STATE */
|
||||
#define CMD1 1 /* SEND_OP_COND */
|
||||
#define CMD8 8 /* SEND_IF_COND */
|
||||
#define CMD8_VHS_2_7_3_6 0x1
|
||||
#define CMD8_ARG(vhs, check_pattern) ((vhs) << 8 | (check_pattern))
|
||||
#define CMD8_ECHO_MASK 0x00000fff
|
||||
#define CMD9 9 /* SEND_CSD */
|
||||
#define CMD10 10 /* SEND_CID */
|
||||
#define CMD12 12 /* STOP_TRANSMISSION */
|
||||
#define CMD13 13 /* SEND_STATUS */
|
||||
#define CMD16 16 /* SET_BLOCKLEN */
|
||||
#define CMD17 17 /* READ_SINGLE_BLOCK */
|
||||
#define CMD18 18 /* READ_MULTIPLE_BLOCK */
|
||||
#define CMD23 23 /* SET_BLOCK_COUNT */
|
||||
#define CMD24 24 /* WRITE_BLOCK */
|
||||
#define CMD25 25 /* WRITE_MULTIPLE_BLOCK */
|
||||
#define CMD32 32 /* ERASE_WR_BLK_START */
|
||||
#define CMD33 33 /* ERASE_WR_BLK_END */
|
||||
#define CMD38 38 /* ERASE */
|
||||
#define CMD55 55 /* APP_CMD */
|
||||
#define CMD58 58 /* READ_OCR */
|
||||
#define ACMD 0x80 /* Application-specific command */
|
||||
#define ACMD13 (ACMD | 13) /* SD_STATUS */
|
||||
#define ACMD23 (ACMD | 23) /* SET_WR_BLK_ERASE_COUNT */
|
||||
#define ACMD41 (ACMD | 41) /* SD_APP_OP_COND */
|
||||
#define ACMD41_HCS (1 << 30)
|
||||
|
||||
#define CMD_TX 0x40 /* Command transmission bit */
|
||||
|
||||
#define R1_MSB 0x00
|
||||
#define R1_SUCCESS 0x00
|
||||
#define R1_IDLE_STATE (1 << 0)
|
||||
#define R1_ERASE_RESET (1 << 1)
|
||||
#define R1_ILLEGAL_COMMAND (1 << 2)
|
||||
#define R1_COM_CRC_ERROR (1 << 3)
|
||||
#define R1_ERASE_SEQUENCE_ERROR (1 << 4)
|
||||
#define R1_ADDRESS_ERROR (1 << 5)
|
||||
#define R1_PARAMETER_ERROR (1 << 6)
|
||||
|
||||
#define TOK_DATA_RESP_MASK 0x1f
|
||||
#define TOK_DATA_RESP_ACCEPTED 0x05
|
||||
#define TOK_DATA_RESP_CRC_ERROR 0x0b
|
||||
#define TOK_DATA_RESP_WR_ERROR 0x0d
|
||||
#define TOK_RD_SINGLE_WR_START_BLOCK 0xfe
|
||||
#define TOK_MULTI_WR_START_BLOCK 0xfc
|
||||
#define TOK_MULTI_WR_STOP_TRAN 0xfd
|
||||
|
||||
/* The SD Status is one data block of 512 bits. */
|
||||
#define SD_STATUS_SIZE (512 / 8)
|
||||
#define SD_STATUS_AU_SIZE(sd_status) ((sd_status)[10] >> 4)
|
||||
|
||||
#define OCR_CCS (1 << 30)
|
||||
|
||||
#define CSD_SIZE 16
|
||||
#define CSD_STRUCTURE(csd) ((csd)[0] >> 6)
|
||||
#define CSD_STRUCTURE_SD_V1_0 0
|
||||
#define CSD_STRUCTURE_SD_V2_0 1
|
||||
#define CSD_SD_V1_0_READ_BL_LEN(csd) ((csd)[5] & 0x0f)
|
||||
#define CSD_SD_V1_0_BLOCK_LEN(csd) (1ull << CSD_SD_V1_0_READ_BL_LEN(csd))
|
||||
#define CSD_SD_V1_0_C_SIZE(csd) \
|
||||
(((csd)[6] & 0x03) << 10 | (csd)[7] << 2 | (csd)[8] >> 6)
|
||||
#define CSD_SD_V1_0_C_SIZE_MULT(csd) \
|
||||
(((csd)[9] & 0x03) << 1 | (csd)[10] >> 7)
|
||||
#define CSD_SD_V1_0_MULT(csd) \
|
||||
(1 << (CSD_SD_V1_0_C_SIZE_MULT(csd) + 2))
|
||||
#define CSD_SD_V1_0_BLOCKNR(csd) \
|
||||
(((uint32_t)CSD_SD_V1_0_C_SIZE(csd) + 1) * CSD_SD_V1_0_MULT(csd))
|
||||
#define CSD_SD_V1_0_CAPACITY(csd) \
|
||||
(CSD_SD_V1_0_BLOCKNR(csd) * CSD_SD_V1_0_BLOCK_LEN(csd))
|
||||
#define CSD_SD_V1_0_SECTOR_SIZE(csd) \
|
||||
(((csd)[10] & 0x3f) << 1 | (csd)[11] >> 7)
|
||||
#define CSD_SD_V1_0_WRITE_BL_LEN(csd) \
|
||||
(((csd)[12] & 0x03) << 2 | (csd)[13] >> 6)
|
||||
#define CSD_SD_V2_0_C_SIZE(csd) \
|
||||
(((csd)[7] & 0x3f) << 16 | (csd)[8] << 8 | (csd)[9])
|
||||
#define CSD_SD_V2_0_CAPACITY(csd) \
|
||||
(((uint64_t)CSD_SD_V2_0_C_SIZE(csd) + 1) << 19)
|
||||
#define CSD_MMC_ERASE_GRP_SIZE(csd) (((csd)[10] & 0x7c) >> 2)
|
||||
#define CSD_MMC_ERASE_GRP_MULT(csd) \
|
||||
(((csd)[10] & 0x03) << 3 | (csd)[11] >> 5)
|
||||
#define CSD_MMC_WRITE_BL_LEN(csd) \
|
||||
(((csd)[12] & 0x03) << 2 | (csd)[13] >> 6)
|
||||
|
||||
typedef enum {
|
||||
CARD_TYPE_MMC = 0x01, /* MMC v3 */
|
||||
CARD_TYPE_SD1 = 0x02, /* SD v1 */
|
||||
CARD_TYPE_SD2 = 0x04, /* SD v2 */
|
||||
CARD_TYPE_SD = CARD_TYPE_SD1 | CARD_TYPE_SD2, /* SD */
|
||||
CARD_TYPE_BLOCK = 0x08 /* Block addressing */
|
||||
} card_type_t;
|
||||
|
||||
static struct mmc_priv {
|
||||
uint8_t status;
|
||||
uint8_t card_type;
|
||||
} mmc_priv[MMC_CONF_DEV_COUNT];
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static uint8_t
|
||||
mmc_spi_xchg(uint8_t dev, uint8_t tx_byte)
|
||||
{
|
||||
uint8_t rx_byte;
|
||||
|
||||
mmc_arch_spi_xfer(dev, &tx_byte, 1, &rx_byte, 1);
|
||||
return rx_byte;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static void
|
||||
mmc_spi_tx(uint8_t dev, const void *buf, size_t cnt)
|
||||
{
|
||||
mmc_arch_spi_xfer(dev, buf, cnt, NULL, 0);
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static void
|
||||
mmc_spi_rx(uint8_t dev, void *buf, size_t cnt)
|
||||
{
|
||||
mmc_arch_spi_xfer(dev, NULL, 0, buf, cnt);
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static bool
|
||||
mmc_wait_ready(uint8_t dev, uint16_t timeout_ms)
|
||||
{
|
||||
rtimer_clock_t timeout_end =
|
||||
RTIMER_NOW() + ((uint32_t)timeout_ms * RTIMER_SECOND + 999) / 1000;
|
||||
uint8_t rx_byte;
|
||||
|
||||
do {
|
||||
rx_byte = mmc_spi_xchg(dev, 0xff);
|
||||
watchdog_periodic();
|
||||
} while(rx_byte != 0xff && RTIMER_CLOCK_LT(RTIMER_NOW(), timeout_end));
|
||||
return rx_byte == 0xff;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static bool
|
||||
mmc_select(uint8_t dev, bool sel)
|
||||
{
|
||||
mmc_arch_spi_select(dev, sel);
|
||||
mmc_spi_xchg(dev, 0xff); /* Dummy clock (force D0) */
|
||||
if(sel && !mmc_wait_ready(dev, 500)) {
|
||||
mmc_select(dev, false);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static uint8_t
|
||||
mmc_send_cmd(uint8_t dev, uint8_t cmd, uint32_t arg)
|
||||
{
|
||||
uint8_t resp, n;
|
||||
|
||||
/* Send a CMD55 prior to a ACMD<n>. */
|
||||
if(cmd & ACMD) {
|
||||
cmd &= ~ACMD;
|
||||
resp = mmc_send_cmd(dev, CMD55, 0);
|
||||
if(resp != R1_SUCCESS && resp != R1_IDLE_STATE) {
|
||||
return resp;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Select the card and wait for ready, except to stop a multiple-block read.
|
||||
*/
|
||||
if(cmd != CMD12) {
|
||||
mmc_select(dev, false);
|
||||
if(!mmc_select(dev, true)) {
|
||||
return 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
/* Send the command packet. */
|
||||
mmc_spi_xchg(dev, CMD_TX | cmd); /* Start & tx bits, cmd index */
|
||||
mmc_spi_xchg(dev, arg >> 24); /* Argument[31..24] */
|
||||
mmc_spi_xchg(dev, arg >> 16); /* Argument[23..16] */
|
||||
mmc_spi_xchg(dev, arg >> 8); /* Argument[15..8] */
|
||||
mmc_spi_xchg(dev, arg); /* Argument[7..0] */
|
||||
switch(cmd) {
|
||||
case CMD0:
|
||||
n = 0x95; /* CMD0(0) CRC7, end bit */
|
||||
break;
|
||||
case CMD8:
|
||||
n = 0x87; /* CMD8(0x1aa) CRC7, end bit */
|
||||
break;
|
||||
default:
|
||||
n = 0x01; /* Dummy CRC7, end bit */
|
||||
break;
|
||||
}
|
||||
mmc_spi_xchg(dev, n);
|
||||
|
||||
/* Receive the command response. */
|
||||
if(cmd == CMD12) {
|
||||
mmc_spi_xchg(dev, 0xff); /* Discard following byte if CMD12. */
|
||||
}
|
||||
/* Wait for the response (max. 10 bytes). */
|
||||
n = 10;
|
||||
do {
|
||||
resp = mmc_spi_xchg(dev, 0xff);
|
||||
} while((resp & 0x80) != R1_MSB && --n);
|
||||
return resp;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static bool
|
||||
mmc_tx_block(uint8_t dev, const void *buf, uint8_t token)
|
||||
{
|
||||
uint8_t resp;
|
||||
|
||||
if(!mmc_wait_ready(dev, 500)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mmc_spi_xchg(dev, token);
|
||||
if(token != TOK_MULTI_WR_STOP_TRAN) {
|
||||
mmc_spi_tx(dev, buf, BLOCK_LEN);
|
||||
mmc_spi_xchg(dev, 0xff); /* Dummy CRC */
|
||||
mmc_spi_xchg(dev, 0xff);
|
||||
|
||||
resp = mmc_spi_xchg(dev, 0xff);
|
||||
if((resp & TOK_DATA_RESP_MASK) != TOK_DATA_RESP_ACCEPTED) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static bool
|
||||
mmc_rx(uint8_t dev, void *buf, size_t cnt)
|
||||
{
|
||||
rtimer_clock_t timeout_end =
|
||||
RTIMER_NOW() + (200ul * RTIMER_SECOND + 999) / 1000;
|
||||
uint8_t token;
|
||||
|
||||
do {
|
||||
token = mmc_spi_xchg(dev, 0xff);
|
||||
watchdog_periodic();
|
||||
} while(token == 0xff && RTIMER_CLOCK_LT(RTIMER_NOW(), timeout_end));
|
||||
if(token != TOK_RD_SINGLE_WR_START_BLOCK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mmc_spi_rx(dev, buf, cnt);
|
||||
mmc_spi_xchg(dev, 0xff); /* Discard CRC. */
|
||||
mmc_spi_xchg(dev, 0xff);
|
||||
return true;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void
|
||||
mmc_arch_cd_changed_callback(uint8_t dev, bool cd)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
if(dev >= MMC_CONF_DEV_COUNT) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(cd) {
|
||||
status = DISK_STATUS_DISK;
|
||||
if(!mmc_arch_get_wp(dev)) {
|
||||
status |= DISK_STATUS_WRITABLE;
|
||||
}
|
||||
} else {
|
||||
status = 0;
|
||||
}
|
||||
mmc_priv[dev].status = status;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static disk_status_t
|
||||
mmc_status(uint8_t dev)
|
||||
{
|
||||
bool cd;
|
||||
struct mmc_priv *priv;
|
||||
|
||||
if(dev >= MMC_CONF_DEV_COUNT) {
|
||||
return DISK_RESULT_INVALID_ARG;
|
||||
}
|
||||
|
||||
cd = mmc_arch_get_cd(dev);
|
||||
priv = &mmc_priv[dev];
|
||||
if(cd == !(priv->status & DISK_STATUS_DISK)) {
|
||||
mmc_arch_cd_changed_callback(dev, cd);
|
||||
}
|
||||
return priv->status;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static disk_status_t
|
||||
mmc_initialize(uint8_t dev)
|
||||
{
|
||||
disk_status_t status;
|
||||
uint8_t n, cmd;
|
||||
card_type_t card_type;
|
||||
rtimer_clock_t timeout_end;
|
||||
uint32_t arg, resp, ocr;
|
||||
struct mmc_priv *priv;
|
||||
|
||||
if(dev >= MMC_CONF_DEV_COUNT) {
|
||||
return DISK_RESULT_INVALID_ARG;
|
||||
}
|
||||
status = mmc_status(dev);
|
||||
if(!(status & DISK_STATUS_DISK)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
mmc_arch_spi_select(dev, false);
|
||||
clock_delay_usec(10000);
|
||||
|
||||
mmc_arch_spi_set_clock_freq(dev, CLOCK_FREQ_CARD_ID_MODE);
|
||||
for(n = 10; n; n--) {
|
||||
mmc_spi_xchg(dev, 0xff); /* Generate 80 dummy clock cycles. */
|
||||
}
|
||||
|
||||
card_type = 0;
|
||||
if(mmc_send_cmd(dev, CMD0, 0) == R1_IDLE_STATE) {
|
||||
timeout_end = RTIMER_NOW() + RTIMER_SECOND;
|
||||
arg = CMD8_ARG(CMD8_VHS_2_7_3_6, 0xaa); /* Arbitrary check pattern */
|
||||
if(mmc_send_cmd(dev, CMD8, arg) == R1_IDLE_STATE) { /* SD v2? */
|
||||
resp = 0;
|
||||
for(n = 4; n; n--) {
|
||||
resp = resp << 8 | mmc_spi_xchg(dev, 0xff);
|
||||
}
|
||||
/* Does the card support 2.7 V - 3.6 V? */
|
||||
if((arg & CMD8_ECHO_MASK) == (resp & CMD8_ECHO_MASK)) {
|
||||
/* Wait for end of initialization. */
|
||||
while(RTIMER_CLOCK_LT(RTIMER_NOW(), timeout_end) &&
|
||||
mmc_send_cmd(dev, ACMD41, ACMD41_HCS) != R1_SUCCESS) {
|
||||
watchdog_periodic();
|
||||
}
|
||||
if(RTIMER_CLOCK_LT(RTIMER_NOW(), timeout_end) &&
|
||||
mmc_send_cmd(dev, CMD58, 0) == R1_SUCCESS) { /* Read OCR. */
|
||||
ocr = 0;
|
||||
for(n = 4; n; n--) {
|
||||
ocr = ocr << 8 | mmc_spi_xchg(dev, 0xff);
|
||||
}
|
||||
card_type = CARD_TYPE_SD2;
|
||||
if(ocr & OCR_CCS) {
|
||||
card_type |= CARD_TYPE_BLOCK;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { /* Not SD v2 */
|
||||
resp = mmc_send_cmd(dev, ACMD41, 0);
|
||||
if(resp == R1_SUCCESS || resp == R1_IDLE_STATE) { /* SD v1 or MMC? */
|
||||
card_type = CARD_TYPE_SD1;
|
||||
cmd = ACMD41;
|
||||
} else {
|
||||
card_type = CARD_TYPE_MMC;
|
||||
cmd = CMD1;
|
||||
}
|
||||
/* Wait for end of initialization. */
|
||||
while(RTIMER_CLOCK_LT(RTIMER_NOW(), timeout_end) &&
|
||||
mmc_send_cmd(dev, cmd, 0) != R1_SUCCESS) {
|
||||
watchdog_periodic();
|
||||
}
|
||||
/* Set block length. */
|
||||
if(!RTIMER_CLOCK_LT(RTIMER_NOW(), timeout_end) ||
|
||||
mmc_send_cmd(dev, CMD16, BLOCK_LEN) != R1_SUCCESS) {
|
||||
card_type = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
priv = &mmc_priv[dev];
|
||||
priv->card_type = card_type;
|
||||
mmc_select(dev, false);
|
||||
|
||||
status = priv->status;
|
||||
if(status & DISK_STATUS_DISK && card_type) { /* OK */
|
||||
mmc_arch_spi_set_clock_freq(dev, CLOCK_FREQ_DATA_XFER_MODE);
|
||||
status |= DISK_STATUS_INIT;
|
||||
} else { /* Failed */
|
||||
status &= ~DISK_STATUS_INIT;
|
||||
}
|
||||
priv->status = status;
|
||||
return status;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static disk_result_t
|
||||
mmc_read(uint8_t dev, void *buff, uint32_t sector, uint32_t count)
|
||||
{
|
||||
if(dev >= MMC_CONF_DEV_COUNT || !count) {
|
||||
return DISK_RESULT_INVALID_ARG;
|
||||
}
|
||||
if(!(mmc_status(dev) & DISK_STATUS_INIT)) {
|
||||
return DISK_RESULT_NO_INIT;
|
||||
}
|
||||
|
||||
if(!(mmc_priv[dev].card_type & CARD_TYPE_BLOCK)) {
|
||||
sector *= SECTOR_SIZE;
|
||||
}
|
||||
|
||||
if(count == 1) {
|
||||
if(mmc_send_cmd(dev, CMD17, sector) == R1_SUCCESS &&
|
||||
mmc_rx(dev, buff, SECTOR_SIZE)) {
|
||||
count = 0;
|
||||
}
|
||||
} else if(mmc_send_cmd(dev, CMD18, sector) == R1_SUCCESS) {
|
||||
do {
|
||||
if(!mmc_rx(dev, buff, SECTOR_SIZE)) {
|
||||
break;
|
||||
}
|
||||
buff = (uint8_t *)buff + SECTOR_SIZE;
|
||||
watchdog_periodic();
|
||||
} while(--count);
|
||||
mmc_send_cmd(dev, CMD12, 0); /* Stop transmission. */
|
||||
}
|
||||
mmc_select(dev, false);
|
||||
return count ? DISK_RESULT_IO_ERROR : DISK_RESULT_OK;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static disk_result_t
|
||||
mmc_write(uint8_t dev, const void *buff, uint32_t sector, uint32_t count)
|
||||
{
|
||||
disk_status_t status;
|
||||
card_type_t card_type;
|
||||
|
||||
if(dev >= MMC_CONF_DEV_COUNT || !count) {
|
||||
return DISK_RESULT_INVALID_ARG;
|
||||
}
|
||||
status = mmc_status(dev);
|
||||
if(!(status & DISK_STATUS_INIT)) {
|
||||
return DISK_RESULT_NO_INIT;
|
||||
}
|
||||
if(!(status & DISK_STATUS_WRITABLE)) {
|
||||
return DISK_RESULT_WR_PROTECTED;
|
||||
}
|
||||
|
||||
card_type = mmc_priv[dev].card_type;
|
||||
if(!(card_type & CARD_TYPE_BLOCK)) {
|
||||
sector *= SECTOR_SIZE;
|
||||
}
|
||||
|
||||
if(count == 1) {
|
||||
if(mmc_send_cmd(dev, CMD24, sector) == R1_SUCCESS &&
|
||||
mmc_tx_block(dev, buff, TOK_RD_SINGLE_WR_START_BLOCK)) {
|
||||
count = 0;
|
||||
}
|
||||
} else {
|
||||
if(card_type & CARD_TYPE_SD) {
|
||||
mmc_send_cmd(dev, ACMD23, count);
|
||||
}
|
||||
if(mmc_send_cmd(dev, CMD25, sector) == R1_SUCCESS) {
|
||||
do {
|
||||
if(!mmc_tx_block(dev, buff, TOK_MULTI_WR_START_BLOCK)) {
|
||||
break;
|
||||
}
|
||||
buff = (uint8_t *)buff + BLOCK_LEN;
|
||||
watchdog_periodic();
|
||||
} while(--count);
|
||||
if(!mmc_tx_block(dev, NULL, TOK_MULTI_WR_STOP_TRAN)) {
|
||||
count = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
mmc_select(dev, false);
|
||||
return count ? DISK_RESULT_IO_ERROR : DISK_RESULT_OK;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static disk_result_t
|
||||
mmc_ioctl(uint8_t dev, uint8_t cmd, void *buff)
|
||||
{
|
||||
card_type_t card_type;
|
||||
disk_result_t res;
|
||||
uint8_t csd[CSD_SIZE], sd_status[SD_STATUS_SIZE], au_size;
|
||||
uint64_t capacity;
|
||||
uint32_t block_size;
|
||||
|
||||
static const uint8_t AU_TO_BLOCK_SIZE[] = {12, 16, 24, 32, 64};
|
||||
|
||||
if(dev >= MMC_CONF_DEV_COUNT) {
|
||||
return DISK_RESULT_INVALID_ARG;
|
||||
}
|
||||
if(!(mmc_status(dev) & DISK_STATUS_INIT)) {
|
||||
return DISK_RESULT_NO_INIT;
|
||||
}
|
||||
|
||||
card_type = mmc_priv[dev].card_type;
|
||||
res = DISK_RESULT_IO_ERROR;
|
||||
|
||||
switch(cmd) {
|
||||
case DISK_IOCTL_CTRL_SYNC:
|
||||
if(mmc_select(dev, true)) {
|
||||
res = DISK_RESULT_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case DISK_IOCTL_GET_SECTOR_COUNT:
|
||||
if(mmc_send_cmd(dev, CMD9, 0) == R1_SUCCESS && mmc_rx(dev, csd, CSD_SIZE)) {
|
||||
capacity = CSD_STRUCTURE(csd) == CSD_STRUCTURE_SD_V2_0 ?
|
||||
CSD_SD_V2_0_CAPACITY(csd) : CSD_SD_V1_0_CAPACITY(csd);
|
||||
*(uint32_t *)buff = capacity / SECTOR_SIZE;
|
||||
res = DISK_RESULT_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case DISK_IOCTL_GET_SECTOR_SIZE:
|
||||
*(uint16_t *)buff = SECTOR_SIZE;
|
||||
res = DISK_RESULT_OK;
|
||||
break;
|
||||
|
||||
case DISK_IOCTL_GET_BLOCK_SIZE:
|
||||
if(card_type & CARD_TYPE_SD2) {
|
||||
if(mmc_send_cmd(dev, ACMD13, 0) == R1_SUCCESS) { /* Read SD status. */
|
||||
mmc_spi_xchg(dev, 0xff);
|
||||
if(mmc_rx(dev, sd_status, SD_STATUS_SIZE)) {
|
||||
au_size = SD_STATUS_AU_SIZE(sd_status);
|
||||
if(au_size) {
|
||||
block_size = au_size <= 0xa ? 8192ull << au_size :
|
||||
(uint32_t)AU_TO_BLOCK_SIZE[au_size - 0xb] << 20;
|
||||
*(uint32_t *)buff = block_size / SECTOR_SIZE;
|
||||
res = DISK_RESULT_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(mmc_send_cmd(dev, CMD9, 0) == R1_SUCCESS &&
|
||||
mmc_rx(dev, csd, CSD_SIZE)) {
|
||||
if(card_type & CARD_TYPE_SD1) {
|
||||
block_size = (uint32_t)(CSD_SD_V1_0_SECTOR_SIZE(csd) + 1) <<
|
||||
CSD_SD_V1_0_WRITE_BL_LEN(csd);
|
||||
} else { /* MMC */
|
||||
block_size = (uint32_t)(CSD_MMC_ERASE_GRP_SIZE(csd) + 1) *
|
||||
(CSD_MMC_ERASE_GRP_MULT(csd) + 1) <<
|
||||
CSD_MMC_WRITE_BL_LEN(csd);
|
||||
}
|
||||
*(uint32_t *)buff = block_size / SECTOR_SIZE;
|
||||
res = DISK_RESULT_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
res = DISK_RESULT_INVALID_ARG;
|
||||
break;
|
||||
}
|
||||
mmc_select(dev, false);
|
||||
return res;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
const struct disk_driver mmc_driver = {
|
||||
.status = mmc_status,
|
||||
.initialize = mmc_initialize,
|
||||
.read = mmc_read,
|
||||
.write = mmc_write,
|
||||
.ioctl = mmc_ioctl
|
||||
};
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/** @} */
|
61
dev/disk/mmc/mmc.h
Normal file
61
dev/disk/mmc/mmc.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Benoît Thébaudeau <benoit@wsystem.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/**
|
||||
* \addtogroup disk
|
||||
* @{
|
||||
*
|
||||
* \defgroup mmc SD/MMC
|
||||
*
|
||||
* SD/MMC device driver.
|
||||
* @{
|
||||
*
|
||||
* \file
|
||||
* Header file for the SD/MMC device driver.
|
||||
*/
|
||||
#ifndef MMC_H_
|
||||
#define MMC_H_
|
||||
|
||||
#include "contiki-conf.h"
|
||||
#include "../disk.h"
|
||||
|
||||
#ifndef MMC_CONF_DEV_COUNT
|
||||
/** Number of SD/MMC devices. */
|
||||
#define MMC_CONF_DEV_COUNT 1
|
||||
#endif
|
||||
|
||||
extern const struct disk_driver mmc_driver;
|
||||
|
||||
#endif /* MMC_H_ */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
Loading…
Add table
Add a link
Reference in a new issue