remove unused library

This commit is contained in:
King Kévin 2018-03-17 13:35:12 +01:00
parent af666455bd
commit 8d0dfeef32
4 changed files with 0 additions and 793 deletions

View File

@ -1,267 +0,0 @@
/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/** library to communicate with a Titan Micro MAX7219 IC attached to a 4-digit 7-segment (code)
* @file led_max7219.c
* @author King Kévin <kingkevin@cuvoodoo.info>
* @date 2017
* @note peripherals used: GPIO @ref led_max7219_gpio, timer @ref led_tm1637_timer
* @warning all calls are blocking
*
* bit vs segment: 0bpabcdefg
* +a+
* f b
* +g+
* e c p
* +d+
*/
/* standard libraries */
#include <stdint.h> // standard integer types
#include <stdlib.h> // general utilities
#include <string.h> // string utilities
/* STM32 (including CM3) libraries */
#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
#include <libopencm3/stm32/rcc.h> // real-time control clock library
#include <libopencm3/stm32/gpio.h> // general purpose input output library
#include <libopencm3/stm32/spi.h> // SPI library
#include <libopencm3/stm32/timer.h> // timer library
#include "global.h" // global utilities
#include "led_max7219.h" // MAX7219 header and definitions
/** @defgroup led_max7219_gpio GPIO used to control MAX7219 IC load line
* @{
*/
#define LED_MAX7219_LOAD_PORT B /**< port for load line */
#define LED_MAX7219_LOAD_PIN 12 /**< pin for load line */
/** @} */
/** @defgroup led_max7219_spi SPI used to communication with MAX7219 IC
* @{
*/
#define LED_MAX7219_SPI 2 /**< SPI to send data */
/** @} */
/** ASCII characters encoded for the 7 segments digit block
* @note starts with space
*/
static const uint8_t ascii_7segments[] = {
0x00, // space
0x06, // ! (I)
0x22, // "
0x1d, // # (o)
0x5b, // $ (s)
0x25, // % (/)
0x5f, // & (6)
0x02, // '
0x4e, // ( ([)
0x78, // )
0x07, // *
0x31, // +
0x04, // ,
0x01, // -
0x04, // . (,)
0x25, // /
0x7e, // 0
0x30, // 1
0x6d, // 2
0x79, // 3
0x33, // 4
0x5b, // 5
0x5f, // 6
0x70, // 7
0x7f, // 8
0x7b, // 9
0x09, // : (=)
0x09, // ; (=)
0x0d, // <
0x09, // =
0x19, // >
0x65, // ?
0x6f, // @
0x77, // A
0x7f, // B
0x4e, // C
0x3d, // D
0x4f, // E
0x47, // F
0x5e, // G
0x37, // H
0x06, // I
0x3c, // J
0x37, // K
0x0e, // L
0x76, // M
0x76, // N
0x7e, // O
0x67, // P
0x6b, // Q
0x66, // R
0x5b, // S
0x0f, // T
0x3e, // U
0x3e, // V (U)
0x3e, // W (U)
0x37, // X (H)
0x3b, // Y
0x6d, // Z
0x4e, // [
0x13, // '\'
0x78, // /
0x62, // ^
0x08, // _
0x20, // `
0x7d, // a
0x1f, // b
0x0d, // c
0x3d, // d
0x6f, // e
0x47, // f
0x7b, // g
0x17, // h
0x04, // i
0x18, // j
0x37, // k
0x06, // l
0x15, // m
0x15, // n
0x1d, // o
0x67, // p
0x73, // q
0x05, // r
0x5b, // s
0x0f, // t
0x1c, // u
0x1c, // v (u)
0x1c, // w (u)
0x37, // x
0x3b, // y
0x6d, // z
0x4e, // { ([)
0x06, // |
0x78, // } ([)
0x01, // ~
};
/** number of display in the chain */
uint8_t lex_max7219_displays = 0;
/** write data on SPI bus and handle load signal
* @param[in] data bytes to write
* @param[in] display display number in chain (0xff for all)
*/
static void led_max7219_write(uint16_t data, uint8_t display)
{
if (lex_max7219_displays<=display && 0xff!=display) { // display no in chain
return;
}
gpio_clear(GPIO(LED_MAX7219_LOAD_PORT), GPIO(LED_MAX7219_LOAD_PIN)); // ensure load pin is low (data is put in MAX7219 register on rising edge)
for (uint8_t i=lex_max7219_displays; i>0; i--) { // go though all displays
while (SPI_SR(SPI(LED_MAX7219_SPI))&SPI_SR_BSY); // wait until not busy
if (0xff==display || i==(display+1)) { // right display or broadcast message
spi_send(SPI(LED_MAX7219_SPI), data); // send data
} else {
spi_send(SPI(LED_MAX7219_SPI), 0x0000); // send no-op command to shift command to correct display or out
}
while (!(SPI_SR(SPI(LED_MAX7219_SPI))&SPI_SR_TXE)); // wait until Tx is empty (reference manual says BSY should also cover this, but it doesn't)
while (SPI_SR(SPI(LED_MAX7219_SPI))&SPI_SR_BSY); // wait until not busy (= transmission completed)
}
gpio_set(GPIO(LED_MAX7219_LOAD_PORT), GPIO(LED_MAX7219_LOAD_PIN)); // create rising edge on load pin for data to be set in MAX7219 register
}
void led_max7219_setup(uint8_t displays)
{
// saved number of displays
lex_max7219_displays = displays;
// configure GPIO for load line
rcc_periph_clock_enable(RCC_GPIO(LED_MAX7219_LOAD_PORT)); // enable clock for GPIO peripheral
gpio_clear(GPIO(LED_MAX7219_LOAD_PORT), GPIO(LED_MAX7219_LOAD_PIN)); // idle low (load on rising edge)
gpio_set_mode(GPIO(LED_MAX7219_LOAD_PORT), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO(LED_MAX7219_LOAD_PIN)); // set as output
// configure SPI peripheral
rcc_periph_clock_enable(RCC_SPI_SCK_PORT(LED_MAX7219_SPI)); // enable clock for GPIO peripheral for clock signal
gpio_set_mode(SPI_SCK_PORT(LED_MAX7219_SPI), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, SPI_SCK_PIN(LED_MAX7219_SPI)); // set as output (max clock speed for MAX7219 is 10 MHz)
rcc_periph_clock_enable(RCC_SPI_MOSI_PORT(LED_MAX7219_SPI)); // enable clock for GPIO peripheral for MOSI signal
gpio_set_mode(SPI_MOSI_PORT(LED_MAX7219_SPI), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, SPI_MOSI_PIN(LED_MAX7219_SPI)); // set as output
rcc_periph_clock_enable(RCC_AFIO); // enable clock for SPI alternate function
rcc_periph_clock_enable(RCC_SPI(LED_MAX7219_SPI)); // enable clock for SPI peripheral
spi_reset(SPI(LED_MAX7219_SPI)); // clear SPI values to default
spi_init_master(SPI(LED_MAX7219_SPI), SPI_CR1_BAUDRATE_FPCLK_DIV_8, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_16BIT, SPI_CR1_MSBFIRST); // initialise SPI as master, divide clock by 8 since max MAX7219 clock is 10 MHz and max SPI PCLK clock is 72 Mhz, depending on which SPI is used, set clock polarity to idle low (as in the datasheet of the MAX7219, but not that important), set clock phase to go high when bit is set (depends on polarity) as data is stored on MAX7219 on rising edge), use 16 bits frames (as used by MAX7219), use MSB first
spi_set_unidirectional_mode(SPI(LED_MAX7219_SPI)); // we only need to transmit data
spi_enable(SPI(LED_MAX7219_SPI)); // enable SPI
}
void led_max7219_on(uint8_t display)
{
led_max7219_write(0x0C01, display); // put in normal operation more (registers remain as set)
}
void led_max7219_off(uint8_t display)
{
led_max7219_write(0x0C00, display); // put in shutdown mode (registers remain as set)
}
void led_max7219_test(bool test, uint8_t display)
{
if (test) {
led_max7219_write(0x0F01, display); // go into display test mode
} else {
led_max7219_write(0x0F00, display); // go into normal operation mode
}
}
void led_max7219_intensity(uint8_t intensity, uint8_t digits, uint8_t display)
{
if (intensity>15) { // intensity must be 0-15 (corresponds to (2*brightness+1)/32)
return;
}
if (digits<1 || digits>8) { // scan limit must bit 0-7
return;
}
led_max7219_write(0x0A00+intensity, display); // set brightness
led_max7219_write(0x0B00+digits-1, display); // set scan limit to display digits
}
bool led_max7219_text(char* text, uint8_t display)
{
for (uint8_t i=0; i<8; i++) { // input text should only contain printable character (8th bit is used for dots)
if ((text[i]&0x7f)<' ' || (text[i]&0x7f)>=' '+LENGTH(ascii_7segments)) {
return false;
}
}
led_max7219_write(0x0900, display); // disable BCD decoding on all 7 digits
for (uint8_t i=0; i<8; i++) { // display text
led_max7219_write(((i+1)<<8)+(ascii_7segments[(text[7-i]&0x7f)-' '])+(text[7-i]&0x80), display); // send digit (in reverse order)
}
return true;
}
void led_max7219_number(uint32_t number, uint8_t dots, uint8_t display)
{
led_max7219_write(0x09FF, display); // enable BCD decoding on all 7 digits
for (uint8_t digit=0; digit<8; digit++) { // go through digits
if (0==digit) { // display 0 on 0 only to first digit
led_max7219_write(((digit+1)<<8) + (number%10) + (((dots>>digit)&0x01)<<7), display); // display digit
} else if (0==number) { // display blank on other digits
led_max7219_write(((digit+1)<<8) + 0x0F + (((dots>>digit)&0x01)<<7), display); // display blank
} else {
led_max7219_write(((digit+1)<<8) + (number%10) + (((dots>>digit)&0x01)<<7), display); // display digit
}
number /= 10; // get next digit
}
}

View File

@ -1,64 +0,0 @@
/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/** library to communicate with a Maxim MAX7219 IC attached to a 8-digit 7-segment (API)
* @file led_max7219.h
* @author King Kévin <kingkevin@cuvoodoo.info>
* @date 2017
* @note peripherals used: GPIO @ref led_max7219_gpio, SPI @ref led_max7219_spi
* @warning all calls are blocking
*/
#pragma once
/** setup communication with MAX7219 IC
* @param[in] displays number of displays in the chain
*/
void led_max7219_setup(uint8_t displays);
/** do nothing (no operation)
* @param[in] display display number in chain (0xff for all)
* @note send it to the last display in the chain to clear the previous command from the chain
*/
void led_max7219_nop(uint8_t display);
/** switch display on
* @param[in] display display number in chain (0xff for all)
*/
void led_max7219_on(uint8_t display);
/** switch display off
* @param[in] display display number in chain (0xff for all)
*/
void led_max7219_off(uint8_t display);
/** switch display in test or normal operation mode
* @param[in] test switch in test mode (else normal operation)
* @param[in] display display number in chain (0xff for all)
*/
void led_max7219_test(bool test, uint8_t display);
/** set display intensity
* @param[in] intensity level to set (0-15)
* @param[in] digits number of digits to display (1-8)
* @param[in] display display number in chain (0xff for all)
*/
void led_max7219_intensity(uint8_t intensity, uint8_t digits, uint8_t display);
/** display text
* @param[in] text text to display (8 characters)
* @param[in] display display number in chain (0xff for all)
* @note use first bit of each character to enable dot
* @return false if string has unsupported characters
*/
bool led_max7219_text(char* text, uint8_t display);
/** display number
* @param[in] number number to display (8 digits max)
* @param[in] dots set bit if dot on corresponding digit should be displayed
* @param[in] display display number in chain (0xff for all)
*/
void led_max7219_number(uint32_t number, uint8_t dots, uint8_t display);

View File

@ -1,409 +0,0 @@
/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/** library for 1-wire protocol as master (code)
* @file onewire_slave.c
* @author King Kévin <kingkevin@cuvoodoo.info>
* @date 2017
* @note peripherals used: GPIO and timer @ref onewire_slave_timer, GPIO @ref onewire_slave_gpio
* @note overdrive mode is not supported
* @implements 1-Wire protocol description from Book of iButton Standards
*/
/* standard libraries */
#include <stdint.h> // standard integer types
#include <stdbool.h> // boolean type
#include <stddef.h> // NULL definition
/* STM32 (including CM3) libraries */
#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
#include <libopencm3/cm3/nvic.h> // interrupt handler
#include <libopencm3/stm32/rcc.h> // real-time control clock library
#include <libopencm3/stm32/gpio.h> // general purpose input output library
#include <libopencm3/stm32/timer.h> // timer library
#include <libopencm3/stm32/exti.h> // external interrupt library
/* own libraries */
#include "global.h" // help macros
#include "onewire_slave.h" // own definitions
/** @defgroup onewire_slave_timer timer used to measure 1-wire signal timing
* @{
*/
#define ONEWIRE_SLAVE_TIMER 2 /**< timer ID */
/** @} */
/** @defgroup onewire_slave_gpio GPIO used for 1-wire signal
* @warning ensure no same pin number on other parts are used for external interrupts
* @note external pull-up resistor on pin is required (< 5 kOhm), generally provided by the master
* @{
*/
#define ONEWIRE_SLAVE_PORT A /**< GPIO port */
#define ONEWIRE_SLAVE_PIN 4 /**< GPIO pin */
/** @} */
/** state of 1-Wire communication */
static volatile enum {
ONEWIRE_STATE_IDLE, /**< no current communication */
ONEWIRE_STATE_RESET, /**< reset pulse has been detected */
ONEWIRE_STATE_WAIT_PRESENCE, /**< waiting before sending the presence pulse */
ONEWIRE_STATE_PULSE_PRESENCE, /**< sending the presence pulse */
ONEWIRE_STATE_ROM_COMMAND, /**< slave is reading ROM command bits */
ONEWIRE_STATE_ROM_READ, /**< slave is sending ROM code in response to ROM command READ ROM */
ONEWIRE_STATE_ROM_MATCH, /**< master is sending ROM code to select slave */
ONEWIRE_STATE_ROM_SEARCH_TRUE, /**< master is searching ROM code, slave will send first bit (not negated) */
ONEWIRE_STATE_ROM_SEARCH_FALSE, /**< master is searching ROM code, slave will send first bit (not negated) */
ONEWIRE_STATE_ROM_SEARCH_SELECT, /**< master is searching ROM code, slave will read selected bit */
ONEWIRE_STATE_FUNCTION_COMMAND, /**< slave is reading function command bits */
ONEWIRE_STATE_FUNCTION_DATA, /**< waiting for user to provide data to transfer */
ONEWIRE_STATE_FUNCTION_READ, /**< slave is reading bits */
ONEWIRE_STATE_FUNCTION_WRITE, /**< slave is writing bits */
ONEWIRE_MAX /** to count the number of possible states */
} onewire_slave_state = ONEWIRE_STATE_IDLE;
static uint8_t onewire_slave_rom_code[8] = {0}; /**< slave ROM code */
volatile bool onewire_slave_function_code_received = false;
volatile uint8_t onewire_slave_function_code = 0;
volatile bool onewire_slave_transfer_complete = false;
static volatile uint8_t bits_buffer = 0; /**< buffer for the incoming bits (up to one byte) */
static volatile uint32_t bits_bit = 0; /**< number of incoming bits */
static volatile uint8_t* onewire_slave_transfer_data = NULL; /**< data to transfer (read or write) */
static volatile uint32_t onewire_slave_transfer_bits = 0; /**< number of bits to transfer */
/** compute CRC for 1-Wire
* @note this CRC-8 uses normal polynomial 0x31, reverse polynomial 0x8C, start value 0x00
* @param[in] data bytes on which to calculate CRC checksum on
* @param[in] length number of bytes in data
* @return computed CRC checksum
*/
static uint8_t onewire_slave_crc(uint8_t* data, uint32_t length)
{
if (NULL==data || 0==length) { // check input
return 0; // wrong input
}
uint8_t crc = 0x00; // initial value
for (uint8_t i=0; i<length; i++) { // go through every byte
crc ^= data[i]; // XOR byte
for (uint8_t b=0; b<8; b++) { // go through every bit
if (crc&0x01) { // least significant bit is set (we are using the reverse way)
crc = (crc>>1)^0x8C; // // shift to the right (for the next bit) and XOR with (reverse) polynomial
} else {
crc >>= 1; // just shift right (for the next bit)
}
}
}
return crc;
}
void onewire_slave_setup(uint8_t family, uint64_t serial)
{
// save ROM code (LSB first)
onewire_slave_rom_code[0] = family;
onewire_slave_rom_code[1] = serial >> 40;
onewire_slave_rom_code[2] = serial >> 32;
onewire_slave_rom_code[3] = serial >> 24;
onewire_slave_rom_code[4] = serial >> 16;
onewire_slave_rom_code[5] = serial >> 8;
onewire_slave_rom_code[6] = serial >> 0;
onewire_slave_rom_code[7] = onewire_slave_crc(onewire_slave_rom_code, 7); // calculate CRC
// setup timer to generate/measure signal timing
rcc_periph_clock_enable(RCC_TIM(ONEWIRE_SLAVE_TIMER)); // enable clock for timer peripheral
timer_reset(TIM(ONEWIRE_SLAVE_TIMER)); // reset timer state
timer_set_mode(TIM(ONEWIRE_SLAVE_TIMER), TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); // set timer mode, use undivided timer clock, edge alignment (simple count), and count up
timer_set_prescaler(TIM(ONEWIRE_SLAVE_TIMER), 1-1); // don't use prescale since this 16 bits timer allows to wait > 480 us used for the reset pulse ( 1/(72E6/1/(2**16))=910us )
// use comparator to time signal (without using the output), starting at slot start
timer_set_period(TIM(ONEWIRE_SLAVE_TIMER), 480*(rcc_ahb_frequency/1000000)-1-1300); // minimum time needed for a reset pulse (480 < Trst), plus hand tuning
timer_set_oc_mode(TIM(ONEWIRE_SLAVE_TIMER), TIM_OC1, TIM_OCM_FROZEN);
timer_set_oc_value(TIM(ONEWIRE_SLAVE_TIMER), TIM_OC1, 16*(rcc_ahb_frequency/1000000)-1); // time to wait before sending the presence pulse, after the rising edge of the reset pulse (15 < Tpdh < 60)
timer_set_oc_mode(TIM(ONEWIRE_SLAVE_TIMER), TIM_OC2, TIM_OCM_FROZEN);
timer_set_oc_value(TIM(ONEWIRE_SLAVE_TIMER), TIM_OC2, 45*(rcc_ahb_frequency/1000000)-1-350); // time to sample the bit after being set (1 < Tlow1 < 15, 60 < Tslot < 120), or stop sending the bit use compare function to detect slave presence (15 = Trdv + 0 < Trelease < 45), plus hand tuning
timer_set_oc_value(TIM(ONEWIRE_SLAVE_TIMER), TIM_OC3, 90*(rcc_ahb_frequency/1000000)-1); // time to stop the presence pulse (60 < Tpdl < 120)
timer_clear_flag(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_UIF | TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF); // clear all interrupt flags
timer_update_on_overflow(TIM(ONEWIRE_SLAVE_TIMER)); // only use counter overflow as UEV source (use overflow as start time or timeout)
timer_enable_irq(TIM(ONEWIRE_SLAVE_TIMER), TIM_DIER_UIE); // enable update interrupt for overflow
nvic_enable_irq(NVIC_TIM_IRQ(ONEWIRE_SLAVE_TIMER)); // catch interrupt in service routine
onewire_slave_function_code_received = false; // reset state
onewire_slave_state = ONEWIRE_STATE_IDLE; // reset state
onewire_slave_transfer_complete = false; // reset state
// setup GPIO with external interrupt
rcc_periph_clock_enable(RCC_GPIO(ONEWIRE_SLAVE_PORT)); // enable clock for GPIO peripheral
gpio_set(GPIO(ONEWIRE_SLAVE_PORT), GPIO(ONEWIRE_SLAVE_PIN)); // idle is high (using pull-up resistor)
gpio_set_mode(GPIO(ONEWIRE_SLAVE_PORT), GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO(ONEWIRE_SLAVE_PIN)); // control output using open drain (this mode also allows to read the input signal)
rcc_periph_clock_enable(RCC_AFIO); // enable alternate function clock for external interrupt
exti_select_source(EXTI(ONEWIRE_SLAVE_PIN), GPIO(ONEWIRE_SLAVE_PORT)); // mask external interrupt of this pin only for this port
exti_set_trigger(EXTI(ONEWIRE_SLAVE_PIN), EXTI_TRIGGER_BOTH); // trigger on signal change
exti_enable_request(EXTI(ONEWIRE_SLAVE_PIN)); // enable external interrupt
nvic_enable_irq(NVIC_EXTI_IRQ(ONEWIRE_SLAVE_PIN)); // enable interrupt
}
bool onewire_slave_function_read(uint8_t* data, size_t size)
{
if (NULL==data || 0==size) { // verify input
return false;
}
if (UINT32_MAX/8<size) { // too many bits to transfer
return false;
}
if (onewire_slave_state!=ONEWIRE_STATE_FUNCTION_DATA) { // not in the right state to transfer data
return false;
}
onewire_slave_transfer_data = data; // save buffer to write to
onewire_slave_transfer_bits = size*8; // number of bits to read
onewire_slave_transfer_complete = false; // reset state
bits_bit = 0; // reset number of bits read
onewire_slave_state = ONEWIRE_STATE_FUNCTION_READ; // read data
return true;
}
bool onewire_slave_function_write(const uint8_t* data, size_t size)
{
if (NULL==data || 0==size) { // verify input
return false;
}
if (onewire_slave_state!=ONEWIRE_STATE_FUNCTION_DATA) { // not in the right state to transfer data
return false;
}
if (UINT32_MAX/8<size) { // too many bits to transfer
return false;
}
onewire_slave_transfer_data = (uint8_t*)data; // save buffer to read from
onewire_slave_transfer_bits = size*8; // number of bits to write
onewire_slave_transfer_complete = false; // reset state
bits_bit = 0; // reset number of bits written
bits_buffer = onewire_slave_transfer_data[0]; // prepare byte to write
onewire_slave_state = ONEWIRE_STATE_FUNCTION_WRITE; // write data
return true;
}
/** interrupt service routine called when 1-Wire signal changes */
void EXTI_ISR(ONEWIRE_SLAVE_PIN)(void)
{
exti_reset_request(EXTI(ONEWIRE_SLAVE_PIN)); // reset interrupt
if (gpio_get(GPIO(ONEWIRE_SLAVE_PORT), GPIO(ONEWIRE_SLAVE_PIN))) { // it's a rising edge
switch (onewire_slave_state) {
case ONEWIRE_STATE_RESET: // reset pulse has ended
timer_disable_counter(TIM(ONEWIRE_SLAVE_TIMER)); // stop timer for reconfiguration
timer_set_counter(TIM(ONEWIRE_SLAVE_TIMER), 0); // reset timer counter
timer_clear_flag(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_CC1IF); // clear flag
timer_enable_irq(TIM(ONEWIRE_SLAVE_TIMER), TIM_DIER_CC1IE); // enable compare interrupt for presence pulse
timer_enable_counter(TIM(ONEWIRE_SLAVE_TIMER)); // start timer to generate timing
onewire_slave_state = ONEWIRE_STATE_WAIT_PRESENCE; // set new stated
break;
case ONEWIRE_STATE_PULSE_PRESENCE: // we stopped sending the presence pulse
onewire_slave_state = ONEWIRE_STATE_ROM_COMMAND; // we now expect a ROM command
bits_bit = 0; // reset buffer bit count
break; // no need to stop the time, the reset will be checked correctly
default: // rising edge is not important is the other cases
break; // nothing to do
}
} else { // it's a falling edge, the beginning of a new signal
timer_disable_counter(TIM(ONEWIRE_SLAVE_TIMER)); // stop timer for reconfiguration
timer_set_counter(TIM(ONEWIRE_SLAVE_TIMER), 0); // reset timer counter
timer_disable_irq(TIM(ONEWIRE_SLAVE_TIMER), TIM_DIER_CC1IE | TIM_DIER_CC2IE | TIM_DIER_CC3IE); // disable all timers
switch (onewire_slave_state) {
case ONEWIRE_STATE_PULSE_PRESENCE: // we started sending the presence pulse
timer_enable_irq(TIM(ONEWIRE_SLAVE_TIMER), TIM_DIER_CC3IE); // enable timer for end of pulse
break;
case ONEWIRE_STATE_ROM_COMMAND: // read ROM command bits
case ONEWIRE_STATE_ROM_MATCH: // read ROM code bits
case ONEWIRE_STATE_FUNCTION_COMMAND: // read function command bits
case ONEWIRE_STATE_ROM_SEARCH_SELECT: // read selected ROM code bit
case ONEWIRE_STATE_FUNCTION_READ: // read function data bit
timer_enable_irq(TIM(ONEWIRE_SLAVE_TIMER), TIM_DIER_CC2IE); // enable timer for reading bit
break;
case ONEWIRE_STATE_ROM_READ: // send ROM code bit
case ONEWIRE_STATE_ROM_SEARCH_TRUE: // send ROM code bit while searching ROM, not negated
case ONEWIRE_STATE_ROM_SEARCH_FALSE: // send ROM code bit while searching ROM, already negated
case ONEWIRE_STATE_FUNCTION_WRITE: // write function data bit
timer_enable_irq(TIM(ONEWIRE_SLAVE_TIMER), TIM_DIER_CC2IE); // enable timer for reading bit
if (0==(bits_buffer&(1<<(bits_bit%8)))) { // need to send a 0 bit
gpio_clear(GPIO(ONEWIRE_SLAVE_PORT), GPIO(ONEWIRE_SLAVE_PIN)); // hold low to send 0 bit
}
break;
case ONEWIRE_STATE_IDLE: // we only expect a reset
default: // we don't expect any falling edge in other states
onewire_slave_state = ONEWIRE_STATE_IDLE; // unexpected signal, reset to idle state
break; // the timer overflow will confirm detect reset pulses
}
timer_clear_flag(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_UIF | TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF); // clear all flags
timer_enable_counter(TIM(ONEWIRE_SLAVE_TIMER)); // start timer to measure the configured timeouts
}
}
/** interrupt service routine called for timer */
void TIM_ISR(ONEWIRE_SLAVE_TIMER)(void)
{
if (timer_interrupt_source(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_UIF)) { // reset timer triggered, verify if it's a reset
if (0==gpio_get(GPIO(ONEWIRE_SLAVE_PORT), GPIO(ONEWIRE_SLAVE_PIN))) { // signal it still low, thus it must be a reset
onewire_slave_state = ONEWIRE_STATE_RESET; // update state
}
timer_disable_counter(TIM(ONEWIRE_SLAVE_TIMER)); // stop timer since there is nothing more to measure
timer_disable_irq(TIM(ONEWIRE_SLAVE_TIMER), TIM_DIER_CC1IE | TIM_DIER_CC2IE | TIM_DIER_CC3IE); // disable all timers
timer_clear_flag(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_UIF | TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF); // clear all flag (I have no idea why the others are get too, even when the interrupt is not enabled)
}
if (timer_interrupt_source(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_CC1IF)) { // wait for presence pulse timer triggered
timer_clear_flag(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_CC1IF); // clear flag
if (ONEWIRE_STATE_WAIT_PRESENCE==onewire_slave_state) { // we can now send the pulse
onewire_slave_state = ONEWIRE_STATE_PULSE_PRESENCE; // save new state
gpio_clear(GPIO(ONEWIRE_SLAVE_PORT), GPIO(ONEWIRE_SLAVE_PIN)); // send presence pulse (will also trigger the timer start)
}
}
if (timer_interrupt_source(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_CC2IF)) { // time to read the bit, or stop writing it
// read/write bit depending on bit
switch (onewire_slave_state) {
case ONEWIRE_STATE_ROM_COMMAND: // read ROM command code bit
case ONEWIRE_STATE_ROM_MATCH: // read ROM code
case ONEWIRE_STATE_FUNCTION_COMMAND: // read function command code bit
case ONEWIRE_STATE_ROM_SEARCH_SELECT: // read selected ROM code bit
case ONEWIRE_STATE_FUNCTION_READ: // read function data bit
if (gpio_get(GPIO(ONEWIRE_SLAVE_PORT), GPIO(ONEWIRE_SLAVE_PIN))) { // bit is set to 1
bits_buffer |= (1<<(bits_bit%8)); // set bit
} else { // bit is set to 0
bits_buffer &= ~(1<<(bits_bit%8)); // clear bit
}
bits_bit++; // go to next bit
break;
case ONEWIRE_STATE_ROM_READ: // write ROM code
case ONEWIRE_STATE_FUNCTION_WRITE: // write function data bit
gpio_set(GPIO(ONEWIRE_SLAVE_PORT), GPIO(ONEWIRE_SLAVE_PIN)); // stop sending bit
bits_bit++; // go to next bit
break;
case ONEWIRE_STATE_ROM_SEARCH_TRUE: // ROM code bit is sent
case ONEWIRE_STATE_ROM_SEARCH_FALSE: // ROM code bit is sent
gpio_set(GPIO(ONEWIRE_SLAVE_PORT), GPIO(ONEWIRE_SLAVE_PIN)); // stop sending bit
break;
default: // these states don't need read/write
break;
}
static uint8_t rom_code_byte; // which byte of the ROM code is processed
// act on bit count
switch (onewire_slave_state) {
case ONEWIRE_STATE_ROM_COMMAND: // read ROM command
if (bits_bit>7) { // complete ROM command code received
bits_bit = 0; // reset buffer
rom_code_byte = 0; // reset ROM code byte index
switch (bits_buffer) { // act depending on ROM command code
case 0x33: // READ ROM
bits_buffer = onewire_slave_rom_code[rom_code_byte]; // prepare to send the first byte
onewire_slave_state = ONEWIRE_STATE_ROM_READ; // write ROM code
break;
case 0xcc: // SKIP ROM
onewire_slave_state = ONEWIRE_STATE_FUNCTION_COMMAND; // now read function command code
break;
case 0x55: // MATCH ROM
onewire_slave_state = ONEWIRE_STATE_ROM_MATCH; // read ROM code
break;
case 0xf0: // SEARCH ROM
bits_buffer = onewire_slave_rom_code[rom_code_byte]; // prepare to search code
onewire_slave_state = ONEWIRE_STATE_ROM_SEARCH_TRUE; // prepare to start sending first new bit
break;
default: // unknown ROM code
onewire_slave_state = ONEWIRE_STATE_IDLE; // go back to default idle state
break;
}
}
break;
case ONEWIRE_STATE_ROM_READ: // send ROM code
if (bits_bit>7) { // complete byte transmitted
rom_code_byte++; // go to next ROM code byte
if (rom_code_byte>LENGTH(onewire_slave_rom_code)) { // complete ROM code send
onewire_slave_state = ONEWIRE_STATE_IDLE; // go back to default idle state
} else {
bits_bit = 0; // reset buffer
bits_buffer = onewire_slave_rom_code[rom_code_byte]; // send next ROM code byte
}
}
break;
case ONEWIRE_STATE_ROM_MATCH: // compare ROM code
if (bits_bit>7) { // complete byte received
if (bits_buffer==onewire_slave_rom_code[rom_code_byte]) { // ROM code byte matches
bits_bit = 0; // reset buffer
rom_code_byte++; // go to next ROM code byte
if (rom_code_byte>=LENGTH(onewire_slave_rom_code)) { // complete ROM code matches
onewire_slave_state = ONEWIRE_STATE_FUNCTION_COMMAND; // now read function command code
}
} else { // ROM code does not match
onewire_slave_state = ONEWIRE_STATE_IDLE; // stop comparing and go back to idle
}
}
break;
case ONEWIRE_STATE_ROM_SEARCH_TRUE: // ROM code bit is send, prepare to send negated version
bits_buffer ^= (1<<bits_bit); // negate bit
onewire_slave_state = ONEWIRE_STATE_ROM_SEARCH_FALSE; // send negated version
break;
case ONEWIRE_STATE_ROM_SEARCH_FALSE: // negated ROM code bit is send, prepare to read selected bit
onewire_slave_state = ONEWIRE_STATE_ROM_SEARCH_SELECT; // read selected
break;
case ONEWIRE_STATE_ROM_SEARCH_SELECT: // check if we are selected
if ((bits_buffer&(1<<(bits_bit-1)))==(onewire_slave_rom_code[rom_code_byte]&(1<<(bits_bit-1)))) { // we have been selected
onewire_slave_state = ONEWIRE_STATE_ROM_SEARCH_TRUE; // prepare to compare next bit
} else { // we are no selected
onewire_slave_state = ONEWIRE_STATE_IDLE; // go back to idle
}
if (bits_bit>7) { // complete byte searched
bits_bit = 0; // reset buffer
rom_code_byte++; // go to next ROM code byte
if (rom_code_byte>=LENGTH(onewire_slave_rom_code)) { // complete ROM code search
onewire_slave_state = ONEWIRE_STATE_FUNCTION_COMMAND; // now read function command code
} else {
bits_buffer = onewire_slave_rom_code[rom_code_byte]; // prepare next ROM code byte
}
}
break;
case ONEWIRE_STATE_FUNCTION_COMMAND: // read function command
if (bits_bit>7) { // complete function command code received
onewire_slave_function_code = bits_buffer; // save function command code to user buffer
onewire_slave_state = ONEWIRE_STATE_FUNCTION_DATA; // let the user transfer data
onewire_slave_function_code_received = true; // notify user
}
break;
case ONEWIRE_STATE_FUNCTION_READ: // save function data bit
if (0==bits_bit%8) { // complete byte received
onewire_slave_transfer_data[(bits_bit-1)/8] = bits_buffer; // save received bytes
}
if (bits_bit>=onewire_slave_transfer_bits) { // read transfer complete
onewire_slave_transfer_data[(bits_bit-1)/8] = bits_buffer; // save last bits
onewire_slave_state = ONEWIRE_STATE_FUNCTION_DATA; // let the user transfer more data
onewire_slave_transfer_complete = true; // notify user
}
break;
case ONEWIRE_STATE_FUNCTION_WRITE: // update function data bit to write
if (0==bits_bit%8) { // complete byte transfer
bits_buffer = onewire_slave_transfer_data[bits_bit/8]; // prepare next byte to write
}
if (bits_bit>=onewire_slave_transfer_bits) { // write transfer complete
onewire_slave_state = ONEWIRE_STATE_FUNCTION_DATA; // let the user transfer more data
onewire_slave_transfer_complete = true; // notify user
}
break;
default: // no action needed
break;
}
timer_clear_flag(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_CC2IF); // clear flag
}
if (timer_interrupt_source(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_CC3IF)) { // end of presence pulse timer triggered
timer_clear_flag(TIM(ONEWIRE_SLAVE_TIMER), TIM_SR_CC3IF); // clear flag
if (ONEWIRE_STATE_PULSE_PRESENCE==onewire_slave_state) {
gpio_set(GPIO(ONEWIRE_SLAVE_PORT), GPIO(ONEWIRE_SLAVE_PIN)); // stop sending presence pulse
// if the pin stays low the reset timer will catch it
}
}
}

View File

@ -1,53 +0,0 @@
/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/** library for 1-wire protocol as slave (API)
* @file onewire_slave.h
* @author King Kévin <kingkevin@cuvoodoo.info>
* @date 2017
* @note peripherals used: timer @ref onewire_slave_timer, GPIO @ref onewire_slave_gpio
* @note overdrive mode is not supported
*/
#pragma once
/** set when a function command code has been received
* @note needs to be cleared by user
*/
extern volatile bool onewire_slave_function_code_received;
/** last function command code received */
extern volatile uint8_t onewire_slave_function_code;
/** set when data read/write transfer has been completed
* @note needs to be cleared by user
*/
extern volatile bool onewire_slave_transfer_complete;
/** setup 1-wire peripheral
* @param[in] family family code for slave ROM code (8 bits)
* @param[in] serial serial number for slave ROM code (48 bits)
*/
void onewire_slave_setup(uint8_t family, uint64_t serial);
/** read data from master
* @param[out] data buffer to save read bits
* @param[in] size number of bytes to read
* @return if transfer initialization succeeded
* @note onewire_slave_transfer_complete is set when transfer is completed
*/
bool onewire_slave_function_read(uint8_t* data, size_t size);
/** write data to master
* @param[in] data data to write
* @param[in] size number of bytes to write
* @return if transfer initialization succeeded
* @note onewire_slave_transfer_complete is set when transfer is completed
*/
bool onewire_slave_function_write(const uint8_t* data, size_t size);