// ################################################################################################# // # << NEORV32: neorv32_onewire.c - 1-Wire Interface Controller HW Driver HW Driver (Source) >> # // # ********************************************************************************************* # // # 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 neorv32_onewire.c * @brief 1-Wire Interface Controller (ONEWIRE) HW driver source file. * * @note These functions should only be used if the ONEWIRE unit was synthesized (IO_ONEWIRE_EN = true). **************************************************************************/ #include "neorv32.h" #include "neorv32_onewire.h" /**********************************************************************//** * Check if ONEWIRE controller was synthesized. * * @return 0 if ONEWIRE was not synthesized, 1 if ONEWIRE is available. **************************************************************************/ int neorv32_onewire_available(void) { if (NEORV32_SYSINFO->SOC & (1 << SYSINFO_SOC_IO_ONEWIRE)) { return 1; } else { return 0; } } /**********************************************************************//** * Reset, configure and enable ONEWIRE interface controller. * * @param[in] t_base Base tick time in ns. * @return 0 if configuration failed, otherwise the actual t_base time in ns is returned. **************************************************************************/ int neorv32_onewire_setup(uint32_t t_base) { const uint8_t PRSC_LUT[4] = {2, 4, 8, 64}; // subset of system clock prescalers // reset NEORV32_ONEWIRE->CTRL = 0; NEORV32_ONEWIRE->DATA = 0; uint32_t t_tick; uint32_t clkdiv; uint32_t clk_prsc_sel = 0; // initial prsc = CLK/2 uint32_t t_clock_x250ps = (4 * 1000 * 1000 * 1000U) / NEORV32_SYSINFO->CLK; // t_clock in multiples of 0.25 ns // find best base tick configuration while (1) { t_tick = t_clock_x250ps * PRSC_LUT[clk_prsc_sel]; clkdiv = (4*t_base) / t_tick; if ((clkdiv > 0) && (clkdiv <= 255)) { // 8-bit break; } else if (clk_prsc_sel < 3) { clk_prsc_sel++; // try next-higher clock prescaler } else { return 0; // failed } } // set new configuration uint32_t ctrl = 0; ctrl |= 1 << ONEWIRE_CTRL_EN; // module enable ctrl |= (clk_prsc_sel & 0x3) << ONEWIRE_CTRL_PRSC0; // clock prescaler ctrl |= ((clkdiv - 1) & 0xff) << ONEWIRE_CTRL_CLKDIV0; // clock divider NEORV32_ONEWIRE->CTRL = ctrl; return (int)((t_clock_x250ps / 4) * PRSC_LUT[clk_prsc_sel] * clkdiv); } /**********************************************************************//** * Enable ONEWIRE controller. **************************************************************************/ void neorv32_onewire_enable(void) { NEORV32_ONEWIRE->CTRL |= (1 << ONEWIRE_CTRL_EN); } /**********************************************************************//** * Disable ONEWIRE controller. **************************************************************************/ void neorv32_onewire_disable(void) { NEORV32_ONEWIRE->CTRL &= ~(1 << ONEWIRE_CTRL_EN); } /**********************************************************************//** * Get current bus state. * * @return 1 if bus is high, 0 if bus is low. **************************************************************************/ int neorv32_onewire_sense(void) { if (NEORV32_ONEWIRE->CTRL & (1 << ONEWIRE_CTRL_SENSE)) { return 1; } else { return 0; } } // ---------------------------------------------------------------------------------------------------------------------------- // NON-BLOCKING functions // ---------------------------------------------------------------------------------------------------------------------------- /**********************************************************************//** * Check if ONEWIRE module is busy. * * @note This function is non-blocking. * * @return 0 if not busy, 1 if busy. **************************************************************************/ int neorv32_onewire_busy(void) { // check busy flag if (NEORV32_ONEWIRE->CTRL & (1 << ONEWIRE_CTRL_BUSY)) { return 1; } else { return 0; } } /**********************************************************************//** * Initiate reset pulse. * * @note This function is non-blocking. **************************************************************************/ void neorv32_onewire_reset(void) { // trigger reset-pulse operation NEORV32_ONEWIRE->CTRL |= 1 << ONEWIRE_CTRL_TRIG_RST; } /**********************************************************************//** * Get bus presence (after RESET). * * @note This function is non-blocking. * * @return 0 if at lest one device is present, -1 otherwise **************************************************************************/ int neorv32_onewire_reset_get_presence(void) { // check presence bit if (NEORV32_ONEWIRE->CTRL & (1 << ONEWIRE_CTRL_PRESENCE)) { return 0; } else { return -1; } } /**********************************************************************//** * Initiate single-bit read. * * @note This function is non-blocking. **************************************************************************/ void neorv32_onewire_read_bit(void) { // output all-one NEORV32_ONEWIRE->DATA = 0xff; // trigger bit operation NEORV32_ONEWIRE->CTRL |= (1 << ONEWIRE_CTRL_TRIG_BIT); } /**********************************************************************//** * Get bit from previous single-bit read operation * * @note This function is non-blocking. * * @return Read bit in bit 0. **************************************************************************/ uint8_t neorv32_onewire_read_bit_get(void) { // return read bit if (NEORV32_ONEWIRE->DATA & (1 << 7)) { // LSB first -> read bit is in MSB return 1; } else { return 0; } } /**********************************************************************//** * Initiate single-bit write. * * @note This function is non-blocking. * * @param[in] bit Bit to be send. **************************************************************************/ void neorv32_onewire_write_bit(uint8_t bit) { // set replicated bit if (bit) { NEORV32_ONEWIRE->DATA = 0xff; } else { NEORV32_ONEWIRE->DATA = 0x00; } // trigger bit operation NEORV32_ONEWIRE->CTRL |= (1 << ONEWIRE_CTRL_TRIG_BIT); } /**********************************************************************//** * Initiate read byte. * * @note This function is non-blocking. **************************************************************************/ void neorv32_onewire_read_byte(void) { // output all-one NEORV32_ONEWIRE->DATA = 0xff; //trigger byte operation NEORV32_ONEWIRE->CTRL |= (1 << ONEWIRE_CTRL_TRIG_BYTE); } /**********************************************************************//** * Get data from previous read byte operation. * * @note This function is non-blocking. * * @return Read byte. **************************************************************************/ uint8_t neorv32_onewire_read_byte_get(void) { // return read bit return (uint8_t)(NEORV32_ONEWIRE->DATA); } /**********************************************************************//** * Initiate write byte. * * @note This function is non-blocking. * * @param[in] byte Byte to be send. **************************************************************************/ void neorv32_onewire_write_byte(uint8_t byte) { // TX data NEORV32_ONEWIRE->DATA = (uint32_t)byte; // and trigger byte operation NEORV32_ONEWIRE->CTRL |= (1 << ONEWIRE_CTRL_TRIG_BYTE); } // ---------------------------------------------------------------------------------------------------------------------------- // BLOCKING functions // ---------------------------------------------------------------------------------------------------------------------------- /**********************************************************************//** * Generate reset pulse and check if any bus device is present. * * @warning This function is blocking! * * @return 0 if at lest one device is present, -1 otherwise **************************************************************************/ int neorv32_onewire_reset_blocking(void) { // trigger reset-pulse operation neorv32_onewire_reset(); // wait for operation to complete while (neorv32_onewire_busy()); // check presence bit return neorv32_onewire_reset_get_presence(); } /**********************************************************************//** * Read single bit. * * @warning This function is blocking! * * @return Read bit in bit 0. **************************************************************************/ uint8_t neorv32_onewire_read_bit_blocking(void) { // trigger read-bit operation neorv32_onewire_read_bit(); // wait for operation to complete while (neorv32_onewire_busy()); // return read bit return neorv32_onewire_read_bit_get(); } /**********************************************************************//** * Write single bit. * * @warning This function is blocking! * * @param[in] bit Bit to be send. **************************************************************************/ void neorv32_onewire_write_bit_blocking(uint8_t bit) { // start single-bit write neorv32_onewire_write_bit(bit); // wait for operation to complete while (neorv32_onewire_busy()); } /**********************************************************************//** * Read byte. * * @warning This function is blocking! * * @return Read byte. **************************************************************************/ uint8_t neorv32_onewire_read_byte_blocking(void) { // initiate read byte neorv32_onewire_read_byte(); // wait for operation to complete while (neorv32_onewire_busy()); // return read byte return neorv32_onewire_read_byte_get(); } /**********************************************************************//** * Write byte. * * @warning This function is blocking! * * @param[in] byte Byte to be send. **************************************************************************/ void neorv32_onewire_write_byte_blocking(uint8_t byte) { // initiate write byte neorv32_onewire_write_byte(byte); // wait for operation to complete while (neorv32_onewire_busy()); }