[sw] add ONEWIRE demo program

This commit is contained in:
stnolting 2022-09-02 09:41:05 +02:00
parent 370d517bfb
commit 9f0af5c083
3 changed files with 673 additions and 0 deletions

View file

@ -0,0 +1,340 @@
// #################################################################################################
// # << NEORV32 - ONEWIRE (1-Wire Interface) Demo Program >> #
// # ********************************************************************************************* #
// # BSD 3-Clause License #
// # #
// # Copyright (c) 2022, Stephan Nolting. 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. #
// # ********************************************************************************************* #
// # The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting #
// #################################################################################################
/**********************************************************************//**
* @file demo_onewire/main.c
* @author Stephan Nolting
* @brief Demo program for the NEORV32 1-Wire interface controller (ONEWIRE).
**************************************************************************/
#include <neorv32.h>
#include <string.h>
// device search algorithm
#include "onewire_aux.h"
/**********************************************************************//**
* @name User configuration
**************************************************************************/
/**@{*/
/** UART BAUD rate */
#define BAUD_RATE 19200
/**@}*/
// Constants
const char hex_c[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
// Prototypes
void show_help(void);
void show_1wire_commands(void);
void read_byte(void);
void write_byte(void);
void scan_bus(void);
uint32_t hexstr_to_uint(char *buffer, uint8_t length);
void onewire_firq_handler(void);
/**********************************************************************//**
* Main function
*
* @note This program requires the ONEWIRE and UART0 modules. Only non-blocking ONEWIRE functions are used.
*
* @return !=0 if setup error
**************************************************************************/
int main() {
// setup UART0 at default baud rate, no parity bits, no HW flow control
neorv32_uart0_setup(BAUD_RATE, PARITY_NONE, FLOW_CONTROL_NONE);
// capture all exceptions and give debug info via UART0
neorv32_rte_setup();
// check if ONEWIRE is implemented at all
if (!neorv32_onewire_available()) {
neorv32_uart0_printf("Error! ONEWIRE module not synthesized!\n");
return -1;
}
// intro
neorv32_uart0_printf("\n\n<<< NEORV32 1-Wire Interface (ONEWIRE) Demo Program >>>\n\n");
// configure ONEWIRE base time
neorv32_uart0_printf("Configuring ONEWIRE time base...\n");
uint32_t t_base_ref = 10000; // reference: t_base = 10000ns = 10us
uint32_t t_base_real = neorv32_onewire_setup(t_base_ref);
neorv32_uart0_printf("t_base: requested = %u ns\n"
" actual value = %u ns\n"
" difference = %i ns\n\n", t_base_ref, t_base_real, ((int)t_base_ref)-((int)t_base_real));
// check bus state - should be high (pulled-high by the pull-up resistor)
neorv32_uart0_printf("Checking bus state... ");
if (neorv32_onewire_sense() != 0) { // bus high?
neorv32_uart0_printf("OK\n");
}
else {
neorv32_uart0_printf("FAILED! Short circuit? Missing pull-up resistor?\n");
}
/*
// install "ONEWIRE operation done interrupt" - this is optional
neorv32_uart0_printf("Installing ONEWIRE 'operation done' interrupt handler...\n");
neorv32_rte_exception_install(ONEWIRE_RTE_ID, onewire_firq_handler);
neorv32_cpu_irq_enable(ONEWIRE_FIRQ_ENABLE); // enable ONEWIRE FIRQ
neorv32_cpu_eint(); // enable global interrupt flag
*/
neorv32_uart0_printf("Starting interactive user console...\n\n");
// show all available commands
show_help();
// console loop
while(1) {
neorv32_uart0_printf("CMD:> ");
char cmd = neorv32_uart0_getc();
neorv32_uart0_putc(cmd); // echo
neorv32_uart0_printf("\n");
if (cmd == 'h') {
show_help();
}
else if (cmd == 'c') {
show_1wire_commands();
}
else if (cmd == 'x') {
neorv32_uart0_printf("Sending reset pulse.\n");
if (neorv32_onewire_reset_blocking()) { neorv32_uart0_printf("No presence detected.\n"); }
else { neorv32_uart0_printf("Device presence detected!\n"); }
}
else if (cmd == '0') {
neorv32_uart0_printf("Writing 0-bit\n");
neorv32_onewire_write_bit_blocking(0);
}
else if (cmd == '1') {
neorv32_uart0_printf("Writing 1-bit\n");
neorv32_onewire_write_bit_blocking(1);
}
else if (cmd == 'b') {
neorv32_uart0_printf("Read bit = %c\n", '0' + (neorv32_onewire_read_bit_blocking() & 1));
}
else if (cmd == 'r') {
read_byte();
}
else if (cmd == 'w') {
write_byte();
}
else if (cmd == 'p') {
if (neorv32_onewire_sense()) { neorv32_uart0_printf("Bus is HIGH.\n"); }
else { neorv32_uart0_printf("Bus is LOW.\n"); }
}
else if (cmd == 's') {
scan_bus();
}
else if ((cmd == 10) || (cmd == 13)) { // line break (enter)
continue;
}
else {
neorv32_uart0_printf("Invalid command. Type 'h' to see the help menu.\n");
}
}
return 0; // should never be reached
}
/**********************************************************************//**
* Show help menu.
**************************************************************************/
void show_help(void) {
neorv32_uart0_printf("Available commands:\n"
" h: Show this text\n"
" c: Show standard 1-Wire commands\n"
" x: Generate reset pulse and check for device presence\n"
" 0: Write single '0' bit\n"
" 1: Write single '1' bit\n"
" b: Read single bit\n"
" r: Read full-byte\n"
" w: Write full-byte\n"
" p: Probe current bus state\n"
" s: Scan bus (get IDs from all devices)\n");
}
/**********************************************************************//**
* Show standard 1-wire commands.
**************************************************************************/
void show_1wire_commands(void) {
neorv32_uart0_printf("Standard 1-wire command bytes:\n"
" 0x33 - Read ROM (for identification)\n"
" 0x55 - Match ROM (access specific device)\n"
" 0xF0 - Search ROM (for device search algorithm)\n"
" 0xCC - Skip ROM (skip addressing)\n");
}
/**********************************************************************//**
* Read full byte from bus.
**************************************************************************/
void read_byte(void) {
int i;
uint8_t tmp = neorv32_onewire_read_byte_blocking();
neorv32_uart0_printf("Read byte = 0b");
// print binary
for (i=7; i>=0; i--) {
if (tmp & (1 << i)) {
neorv32_uart0_putc('1');
}
else {
neorv32_uart0_putc('0');
}
}
// print hexadecimal
neorv32_uart0_printf(" (0x");
neorv32_uart0_putc(hex_c[(tmp >> 4) & 0x0f]);
neorv32_uart0_putc(hex_c[(tmp >> 0) & 0x0f]);
neorv32_uart0_printf(")\n");
}
/**********************************************************************//**
* Write full byte to bus.
**************************************************************************/
void write_byte(void) {
char terminal_buffer[4];
// enter address
neorv32_uart0_printf("Enter write data (2 hex chars): 0x");
neorv32_uart0_scan(terminal_buffer, 2+1, 1); // 2 hex chars for address plus '\0'
uint8_t wdata = (uint8_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
// write to bus
neorv32_uart0_printf("\nWriting 0x");
neorv32_uart0_putc(hex_c[(wdata >> 4) & 0x0f]);
neorv32_uart0_putc(hex_c[(wdata >> 0) & 0x0f]);
neorv32_onewire_write_byte_blocking(wdata);
neorv32_uart0_printf("\n");
}
/**********************************************************************//**
* Scan bus for devices and print IDs.
**************************************************************************/
void scan_bus(void) {
neorv32_uart0_printf("Scanning bus...\n");
// APPLICATION NOTE 187 "1-Wire Search Algorithm" by Maxim Integrated
// modified for the NEORV32 Processor
int res, i, cnt;
cnt = 0;
res = OWFirst();
while (res) {
neorv32_uart0_printf(" > Family code: 0x");
neorv32_uart0_putc(hex_c[(ROM_NO[0] >> 4) & 0x0f]);
neorv32_uart0_putc(hex_c[(ROM_NO[0] >> 0) & 0x0f]);
neorv32_uart0_printf(", ID: ");
for (i=6; i>0; i--) {
neorv32_uart0_putc('0');
neorv32_uart0_putc('x');
neorv32_uart0_putc(hex_c[(ROM_NO[i] >> 4) & 0x0f]);
neorv32_uart0_putc(hex_c[(ROM_NO[i] >> 0) & 0x0f]);
if (i != 1) {
neorv32_uart0_putc(' ');
}
}
neorv32_uart0_printf(", CRC: 0x");
neorv32_uart0_putc(hex_c[(ROM_NO[7] >> 4) & 0x0f]);
neorv32_uart0_putc(hex_c[(ROM_NO[7] >> 0) & 0x0f]);
neorv32_uart0_printf("\n");
cnt++;
res = OWNext();
}
neorv32_uart0_printf("Devices found: %u\n", cnt);
}
/**********************************************************************//**
* Helper function to convert N hex char string into uint32_t.
*
* @param[in] buffer Pointer to array of chars to convert into number.
* @param[in] length Length of the conversion string.
* @return Converted 32-bit number.
**************************************************************************/
uint32_t hexstr_to_uint(char *buffer, uint8_t length) {
uint32_t res = 0, d = 0;
char c = 0;
while (length--) {
c = *buffer++;
if ((c >= '0') && (c <= '9'))
d = (uint32_t)(c - '0');
else if ((c >= 'a') && (c <= 'f'))
d = (uint32_t)((c - 'a') + 10);
else if ((c >= 'A') && (c <= 'F'))
d = (uint32_t)((c - 'A') + 10);
else
d = 0;
res = res + (d << (length*4));
}
return res;
}
/**********************************************************************//**
* ONEWIRE operation done interrupt handler.
**************************************************************************/
void onewire_firq_handler(void) {
neorv32_cpu_csr_write(CSR_MIP, ~(1 << ONEWIRE_FIRQ_PENDING)); // ack FIRQ
neorv32_uart0_printf(" <<DONE IRQ>> ");
}

View file

@ -0,0 +1,40 @@
#################################################################################################
# << NEORV32 - Application Makefile >> #
# ********************************************************************************************* #
# Make sure to add the RISC-V GCC compiler's bin folder to your PATH environment variable. #
# ********************************************************************************************* #
# BSD 3-Clause License #
# #
# Copyright (c) 2021, Stephan Nolting. 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. #
# ********************************************************************************************* #
# The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting #
#################################################################################################
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
NEORV32_HOME ?= ../../..
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -0,0 +1,293 @@
// APPLICATION NOTE 187 "1-Wire Search Algorithm" by Maxim Integrated
// https://www.maximintegrated.com/en/design/technical-documents/app-notes/1/187.html
// modified for the NEORV32 Processor
#ifndef onewire_aux_h
#define onewire_aux_h
#include <neorv32.h>
// definitions
#define FALSE 0
#define TRUE 1
static unsigned char dscrc_table[] = {
0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65,
157,195, 33,127,252,162, 64, 30, 95, 1,227,189, 62, 96,130,220,
35,125,159,193, 66, 28,254,160,225,191, 93, 3,128,222, 60, 98,
190,224, 2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255,
70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89, 7,
219,133,103, 57,186,228, 6, 88, 25, 71,165,251,120, 38,196,154,
101, 59,217,135, 4, 90,184,230,167,249, 27, 69,198,152,122, 36,
248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91, 5,231,185,
140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205,
17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80,
175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238,
50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115,
202,148,118, 40,171,245, 23, 73, 8, 86,180,234,105, 55,213,139,
87, 9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22,
233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168,
116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53};
// method declarations
int OWFirst();
int OWNext();
int OWVerify();
void OWTargetSetup(unsigned char family_code);
void OWFamilySkipSetup();
int OWSearch();
unsigned char docrc8(unsigned char value);
// global search state
unsigned char ROM_NO[8];
int LastDiscrepancy;
int LastFamilyDiscrepancy;
int LastDeviceFlag;
unsigned char crc8;
//--------------------------------------------------------------------------
// Find the 'first' devices on the 1-Wire bus
// Return TRUE : device found, ROM number in ROM_NO buffer
// FALSE : no device present
//
int OWFirst()
{
// reset the search state
LastDiscrepancy = 0;
LastDeviceFlag = FALSE;
LastFamilyDiscrepancy = 0;
return OWSearch();
}
//--------------------------------------------------------------------------
// Find the 'next' devices on the 1-Wire bus
// Return TRUE : device found, ROM number in ROM_NO buffer
// FALSE : device not found, end of search
//
int OWNext()
{
// leave the search state alone
return OWSearch();
}
//--------------------------------------------------------------------------
// Perform the 1-Wire Search Algorithm on the 1-Wire bus using the existing
// search state.
// Return TRUE : device found, ROM number in ROM_NO buffer
// FALSE : device not found, end of search
//
int OWSearch()
{
int id_bit_number;
int last_zero, rom_byte_number, search_result;
int id_bit, cmp_id_bit;
unsigned char rom_byte_mask, search_direction;
// initialize for search
id_bit_number = 1;
last_zero = 0;
rom_byte_number = 0;
rom_byte_mask = 1;
search_result = 0;
crc8 = 0;
// if the last call was not the last one
if (!LastDeviceFlag)
{
// 1-Wire reset
if (neorv32_onewire_reset_blocking())
{
// reset the search
LastDiscrepancy = 0;
LastDeviceFlag = FALSE;
LastFamilyDiscrepancy = 0;
return FALSE;
}
// issue the search command
neorv32_onewire_write_byte_blocking(0xF0);
// loop to do the search
do
{
// read a bit and its complement
id_bit = neorv32_onewire_read_bit_blocking();
cmp_id_bit = neorv32_onewire_read_bit_blocking();
// check for no devices on 1-wire
if ((id_bit == 1) && (cmp_id_bit == 1))
break;
else
{
// all devices coupled have 0 or 1
if (id_bit != cmp_id_bit)
search_direction = id_bit; // bit write value for search
else
{
// if this discrepancy if before the Last Discrepancy
// on a previous next then pick the same as last time
if (id_bit_number < LastDiscrepancy)
search_direction = ((ROM_NO[rom_byte_number] & rom_byte_mask) > 0);
else
// if equal to last pick 1, if not then pick 0
search_direction = (id_bit_number == LastDiscrepancy);
// if 0 was picked then record its position in LastZero
if (search_direction == 0)
{
last_zero = id_bit_number;
// check for Last discrepancy in family
if (last_zero < 9)
LastFamilyDiscrepancy = last_zero;
}
}
// set or clear the bit in the ROM byte rom_byte_number
// with mask rom_byte_mask
if (search_direction == 1)
ROM_NO[rom_byte_number] |= rom_byte_mask;
else
ROM_NO[rom_byte_number] &= ~rom_byte_mask;
// serial number search direction write bit
neorv32_onewire_write_bit_blocking(search_direction);
// increment the byte counter id_bit_number
// and shift the mask rom_byte_mask
id_bit_number++;
rom_byte_mask <<= 1;
// if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask
if (rom_byte_mask == 0)
{
docrc8(ROM_NO[rom_byte_number]); // accumulate the CRC
rom_byte_number++;
rom_byte_mask = 1;
}
}
}
while(rom_byte_number < 8); // loop until through all ROM bytes 0-7
// if the search was successful then
if (!((id_bit_number < 65) || (crc8 != 0)))
{
// search successful so set LastDiscrepancy,LastDeviceFlag,search_result
LastDiscrepancy = last_zero;
// check for last device
if (LastDiscrepancy == 0)
LastDeviceFlag = TRUE;
search_result = TRUE;
}
}
// if no device found then reset counters so next 'search' will be like a first
if (!search_result || !ROM_NO[0])
{
LastDiscrepancy = 0;
LastDeviceFlag = FALSE;
LastFamilyDiscrepancy = 0;
search_result = FALSE;
}
return search_result;
}
//--------------------------------------------------------------------------
// Verify the device with the ROM number in ROM_NO buffer is present.
// Return TRUE : device verified present
// FALSE : device not present
//
int OWVerify()
{
unsigned char rom_backup[8];
int i,rslt,ld_backup,ldf_backup,lfd_backup;
// keep a backup copy of the current state
for (i = 0; i < 8; i++)
rom_backup[i] = ROM_NO[i];
ld_backup = LastDiscrepancy;
ldf_backup = LastDeviceFlag;
lfd_backup = LastFamilyDiscrepancy;
// set search to find the same device
LastDiscrepancy = 64;
LastDeviceFlag = FALSE;
if (OWSearch())
{
// check if same device found
rslt = TRUE;
for (i = 0; i < 8; i++)
{
if (rom_backup[i] != ROM_NO[i])
{
rslt = FALSE;
break;
}
}
}
else
rslt = FALSE;
// restore the search state
for (i = 0; i < 8; i++)
ROM_NO[i] = rom_backup[i];
LastDiscrepancy = ld_backup;
LastDeviceFlag = ldf_backup;
LastFamilyDiscrepancy = lfd_backup;
// return the result of the verify
return rslt;
}
//--------------------------------------------------------------------------
// Setup the search to find the device type 'family_code' on the next call
// to OWNext() if it is present.
//
void OWTargetSetup(unsigned char family_code)
{
int i;
// set the search state to find SearchFamily type devices
ROM_NO[0] = family_code;
for (i = 1; i < 8; i++)
ROM_NO[i] = 0;
LastDiscrepancy = 64;
LastFamilyDiscrepancy = 0;
LastDeviceFlag = FALSE;
}
//--------------------------------------------------------------------------
// Setup the search to skip the current device type on the next call
// to OWNext().
//
void OWFamilySkipSetup()
{
// set the Last discrepancy to last family discrepancy
LastDiscrepancy = LastFamilyDiscrepancy;
LastFamilyDiscrepancy = 0;
// check for end of list
if (LastDiscrepancy == 0)
LastDeviceFlag = TRUE;
}
//--------------------------------------------------------------------------
// Calculate the CRC8 of the byte value provided with the current
// global 'crc8' value.
// Returns current global crc8 value
//
unsigned char docrc8(unsigned char value)
{
// See Application Note 27
// TEST BUILD
crc8 = dscrc_table[crc8 ^ value];
return crc8;
}
#endif // onewire_aux_h