Challenge

Project 2 - Design and develop the web based Temperature control system using Beagle Bone Black.

Steps:

  1. Declare the device information in the device tree by adding the compatible string and properties for the sensor.

  2. Initialize the I2C interface for the sensor by registering it with the I2C subsystem.

  3. Create a device driver structure that contains the necessary callbacks, such as probe(), read(), and other optional functions.

  4. In the probe() function, register the platform device for the MCP9808 Temperature Sensor with the driver/misc subsystem.

  5. In the read() function, send the appropriate I2C messages to read the temperature data from the sensor and copy it to the user space.

  6. Set up the GPIO interrupt for the alert pin on the BBB and configure the interrupt handler.

  7. Based on the interrupt, turn the motor on or off as per the temperature thresholds set through the DTS file

Once the device driver is written, We can write a user space application to read the temperature data at regular intervals and store it in a database. The web page can be developed using HTML and JavaScript to retrieve the temperature data from the database and plot it as a graph.

The expected outcome of this project is to learn the various steps involved in building an embedded Linux target, configuring the GPIO and I2C subsystem, and understanding the device driver development process.

 

#include
#include
#include
#include
#include
#include
#include
#include

#define MCP9808_TEMP_REG 0x05
#define MCP9808_CONFIG_REG 0x01
#define MCP9808_T_LOWER_REG 0x02
#define MCP9808_T_UPPER_REG 0x03

struct mcp9808_data {
struct i2c_client *client;
struct platform_device *pdev;
int irq_gpio;
int threshold;
};

static irqreturn_t mcp9808_alert_handler(int irq, void *data) {
struct mcp9808_data *mcp = data;
int temp;
u8 buf[2];

i2c_smbus_read_i2c_block_data(mcp->client, MCP9808_TEMP_REG, 2, buf);
temp = ((buf[0] & 0x0F) << 8>

if (temp > mcp->threshold) {
gpio_set_value_cansleep(mcp->irq_gpio, 1);
} else {
gpio_set_value_cansleep(mcp->irq_gpio, 0);
}

return IRQ_HANDLED;
}

static int mcp9808_probe(struct i2c_client *client, const struct i2c_device_id *id) {
struct mcp9808_data *mcp;
struct platform_device *pdev;
struct device *dev = &client->dev;
int ret;

mcp = devm_kzalloc(dev, sizeof(struct mcp9808_data), GFP_KERNEL);
if (!mcp) {
dev_err(dev, "Failed to allocate memoryn");
return -ENOMEM;
}

mcp->client = client;
mcp->threshold = 0;

// Set T_LOWER and T_UPPER from device tree
struct device_node *np = dev->of_node;
if (np) {
u32 t_lower, t_upper;
of_property_read_u32(np, "t-lower", &t_lower);
of_property_read_u32(np, "t-upper", &t_upper);

i2c_smbus_write_word_data(mcp->client, MCP9808_T_LOWER_REG, t_lower);
i2c_smbus_write_word_data(mcp->client, MCP9808_T_UPPER_REG, t_upper);

dev_info(dev, "Set T_LOWER = �nd T_UPPER = %dn", t_lower, t_upper);
}

// Register the platform device
pdev = platform_device_alloc("mcp9808", -1);
if (!pdev)

{

dev_err(dev, "Failed to allocate platform devicen"); return -ENOMEM;

}

mcp->pdev = pdev;

ret = platform_device_add_data(pdev, mcp, sizeof(struct mcp9808_data));
if (ret) {
dev_err(dev, "Failed to add platform device datan");
platform_device_put(pdev);
return ret;
}

ret = platform_device_add(pdev);
if (ret) {
dev_err(dev, "Failed to add platform devicen");
platform_device_unregister(pdev);
return ret;
}

// Register the interrupt handler
mcp->irq_gpio = of_get_named_gpio(dev->of_node, "alert-gpio", 0);
if (gpio_is_valid(mcp->irq_gpio)) {
ret = gpio_request(mcp->irq_gpio, "mcp9808-alert");
if (ret) {
dev_err(dev, "Failed to request gpio %dn", mcp->irq_gpio);
platform_device_unregister(mcp->pdev);
return ret;
}

ret = gpio_direction_output(mcp->irq_gpio, 0);
if (ret) {
dev_err(dev, "Failed to set gpio �irectionn", mcp->irq_gpio);
gpio_free(mcp->irq_gpio);
platform_device_unregister(mcp->pdev);
return ret;
}

ret = gpio_to_irq(mcp->irq_gpio);
if (ret < 0 xss=removed>dev_err(dev, "Failed to get irq from gpio %dn", mcp->irq_gpio);
gpio_free(mcp->irq_gpio);
platform_device_unregister(mcp->pdev);
return ret;
}

ret = request_irq(ret, mcp9808_alert_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "mcp9808-alert", mcp);
if (ret) {
dev_err(dev, "Failed to request irqn");
gpio_free(mcp->irq_gpio);
platform_device_unregister(mcp->pdev);
return ret;
}

dev_info(dev, "Registered interrupt handlern");
}

dev_info(dev, "MCP9808 device detectedn");
return 0;

}

static int mcp9808_remove(struct i2c_client *client) { struct mcp9808_data *mcp = i2c_get_clientdata(client);

if (gpio_is_valid(mcp->irq_gpio)) {
free_irq(gpio_to_irq(mcp->irq_gpio), mcp);
gpio_free(mcp->irq_gpio);
}

platform_device_unregister(mcp->pdev);

return 0;

}

static const struct of_device_id mcp9808_of_match[] = { { .compatible = "microchip,mcp9808", }, {}, };

MODULE_DEVICE_TABLE(of, mcp9808_of_match);

static const struct i2c_device_id mcp9808_id[] = { { "mcp9808", 0 }, { }, }; MODULE_DEVICE_TABLE(i2c, mcp9808_id);

static struct i2c_driver mcp9808_driver = { .driver = { .name = "mcp9808", .of_match_table = mcp9808_of_match, }, .probe = mcp9808_probe, .remove = mcp9808_remove, .id_table = mcp9808_id, };

module_i2c_driver(mcp9808_driver);

MODULE_AUTHOR("Author name"); MODULE_DESCRIPTION("MCP9808 temperature sensor driver"); MODULE_LICENSE("GPL v2");

 

Creating web page:

 

 

 

 

 

 

 

 

 

 

 

 

INTERFACING WITH DATA BASE:

#include

#include

#include

#include

 

/// Prints out a MySQL error message and exits

///

/// This function should be called after a MySQL error has been encountered.  This function will then

/// notify the user of the error that has occurred, clean up the existing MySQL connection, and then

/// exit the program.

///

/// @param The MySQL connection to clean up before exiting

void error_exit(MYSQL *con)

{

fprintf(stderr, "%sn", mysql_error(con));

 

if (con != NULL)

{

mysql_close(con);

}

           

exit(1);

}

 

int main(int argc, const char *argv[])

{

// Initialize a connection to MySQL

MYSQL *con = mysql_init(NULL);

if(con == NULL)

{

error_exit(con);

}

           

// Connect to MySQL

// Here we pass in:

//  host name => localhost

//  user name => bone

//  password => bone

//  database name => TempDB

if (mysql_real_connect(con, "localhost", "bone", "bone", "TempDB", 0, NULL, 0) == NULL)

{

error_exit(con);

}

 

// Create the TempMeas database (if it doesn't already exist)

if (mysql_query(con, "CREATE TABLE IF NOT EXISTS TempMeas(MeasTime DATETIME, Temp DOUBLE)"))

{

error_exit(con);

}

 

// Initialize a MySQL statement

MYSQL_STMT *stmt = mysql_stmt_init(con);

if (stmt == NULL)

{

error_exit(con);

}

           

// Set out insert query as the MySQL statement

const char *query = "INSERT INTO TempMeas(MeasTime, Temp) VALUES(NOW(), ?)";

if (mysql_stmt_prepare(stmt, query, strlen(query)))

{

error_exit(con);

}

 

// Create the MySQL bind structure to store the data that we are going to insert

double temp = 0.0;

MYSQL_BIND bind;

memset(&bind, 0, sizeof(bind));

bind.buffer_type = MYSQL_TYPE_DOUBLE;

bind.buffer = (char *)&temp;

bind.buffer_length = sizeof(double);

 

// Bind the data structure to the MySQL statement

if (mysql_stmt_bind_param(stmt, &bind))

{

error_exit(con);

}

 

// Insert multiple records into the database,

// with different data each time

for (int i = 0; i < 10>

{

temp = (float)i;

mysql_stmt_execute(stmt);

}

 

// Close the MySQL connection

mysql_close(con);

 

return 0;

}

Your portfolio, next

Ship work like this
in your own course.

Talk to a career counsellor

Free 20-minute call. We'll map the right course to where you want to work.

By submitting you agree to our Terms and Privacy Policy.