├── .editorconfig ├── one-slave ├── memory │ └── offset.h ├── devices │ ├── one-2408-pwm.h │ ├── one-2408.h │ ├── one-2408-pwm.c │ └── one-2408.c ├── one-slave.h └── one-slave.c ├── .gitattributes ├── README.md ├── .gitignore └── hardware └── main.svg /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | indent_style = tab 3 | indent_size = 4 4 | -------------------------------------------------------------------------------- /one-slave/memory/offset.h: -------------------------------------------------------------------------------- 1 | #ifndef OFFSET_H 2 | #define OFFSET_H 3 | 4 | #define OFS_IN 0x00 5 | #define OFS_OUT 0x01 6 | #define OFS_DIR 0x02 7 | #define OFS_IFG 0x03 8 | #define OFS_IES 0x04 9 | #define OFS_IE 0x05 10 | #define OFS_SEL 0x06 11 | #define OFS_REN 0x07 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /one-slave/devices/one-2408-pwm.h: -------------------------------------------------------------------------------- 1 | #ifndef ONE_2408_PWM_H 2 | #define ONE_2408_PWM_H 3 | 4 | #include 5 | #include 6 | 7 | #define ONE_2408_PWM_FC 0x29 8 | 9 | void one_2408_pwm_process(void * device); 10 | void one_2408_pwm_init(void * device); 11 | 12 | typedef volatile unsigned char reg8_type; 13 | typedef volatile unsigned int reg16_type; 14 | 15 | typedef struct { 16 | reg8_type * port_base; 17 | reg16_type * timer_ccr; 18 | uint8_t out_bit; 19 | uint8_t reg_csr; 20 | } one_2408_pwm; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /one-slave/devices/one-2408.h: -------------------------------------------------------------------------------- 1 | #ifndef ONE_2408_H 2 | #define ONE_2408_H 3 | 4 | #include 5 | #include 6 | 7 | #define ONE_2408_FC 0x29 8 | #define ONE_2408_DEF_PDIR 0xFF 9 | 10 | void one_2408_process(void * device); 11 | void one_2408_init(void * device); 12 | uint8_t one_2408_condition(void * device); 13 | 14 | typedef volatile unsigned char reg_type; 15 | 16 | typedef struct { 17 | reg_type * port_base; 18 | uint8_t reg_csr; 19 | uint8_t reg_cond_mask; 20 | uint8_t reg_cond_pol; 21 | } one_2408; 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /one-slave/one-slave.h: -------------------------------------------------------------------------------- 1 | #ifndef ONE_SLAVE_H 2 | #define ONE_SLAVE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "memory/offset.h" 8 | 9 | #ifndef ONE_CONFIG_EXTERNAL 10 | #define ONE_PORT 2 11 | #define ONE_B_IN 5 12 | #define ONE_B_OUT 4 13 | #endif 14 | 15 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 16 | 17 | typedef struct { 18 | uint64_t rom; 19 | void (* process)(void * device); 20 | void (* init)(void * device); 21 | uint8_t (* condition)(void * device); 22 | void * device; 23 | } one_device; 24 | 25 | extern uint8_t one_reset_flag; 26 | 27 | void one_init(one_device * d, const uint8_t count); 28 | void one_process_state(); 29 | uint8_t one_condition_dummy(void * device); 30 | 31 | uint8_t one_read_byte(); 32 | void one_write_byte(uint8_t data); 33 | uint16_t crc16(uint8_t input, uint16_t seed); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # onewire-slave 2 | 1-wire1 slave device emulation library for MSP430 microcontrollers. [Open project wiki](https://github.com/resetnow/one-slave/wiki/) 3 | 4 | ## Features 5 | 6 | * Up to 4 emulated devices on a single microcontroller 7 | * Interrupt-driven, uses low-power mode when idle 8 | * Easily extensible 9 | 10 | ## Status & TODO 11 | 12 | - [x] Basic protocol handling, reading/writing timeslots 13 | - [x] Search ROM command 14 | - [x] Match ROM command 15 | - [x] 8-bit switch implementation (one-2408) 16 | - [x] Extension API documentation 17 | 18 | ## Hardware 19 | 20 | This library version was tested on MSP430G2553; it sholud work on similiar microconrollers from the same family. 21 | 22 | Refer to [this wiki page](https://github.com/resetnow/one-slave/wiki/Schematics) for schematics and further hardware-related info. 23 | 24 | 1 — 1-Wire is a trademark of [Maxim Integrated](http://www.maxim-ic.com). 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Libraries 8 | *.lib 9 | *.a 10 | 11 | # Shared objects (inc. Windows DLLs) 12 | *.dll 13 | *.so 14 | *.so.* 15 | *.dylib 16 | 17 | # Executables 18 | *.exe 19 | *.out 20 | *.app 21 | *.i*86 22 | *.x86_64 23 | *.hex 24 | 25 | # ========================= 26 | # Operating System Files 27 | # ========================= 28 | 29 | # OSX 30 | # ========================= 31 | 32 | .DS_Store 33 | .AppleDouble 34 | .LSOverride 35 | 36 | # Icon must ends with two \r. 37 | Icon 38 | 39 | # Thumbnails 40 | ._* 41 | 42 | # Files that might appear on external disk 43 | .Spotlight-V100 44 | .Trashes 45 | 46 | # Windows 47 | # ========================= 48 | 49 | # Windows image file caches 50 | Thumbs.db 51 | ehthumbs.db 52 | 53 | # Folder config file 54 | Desktop.ini 55 | 56 | # Recycle Bin used on file shares 57 | $RECYCLE.BIN/ 58 | 59 | # Windows Installer files 60 | *.cab 61 | *.msi 62 | *.msm 63 | *.msp 64 | 65 | # C preprocessor 66 | *.pp 67 | 68 | # Configuration-specific folders 69 | Debug 70 | Release 71 | 72 | # Code Composer Studio files 73 | .cproject 74 | .ccsproject 75 | .project 76 | targetConfigs 77 | .settings 78 | .launches 79 | lnk_*.cmd 80 | 81 | main.c -------------------------------------------------------------------------------- /one-slave/devices/one-2408-pwm.c: -------------------------------------------------------------------------------- 1 | #include "one-2408-pwm.h" 2 | #include "one-slave.h" 3 | 4 | #define REG_OFFSET 0x88 5 | #define REG_PAGE_LENGTH 0x08 6 | 7 | #define REG_PIO_LOGIC 0x00 8 | #define REG_OUT_LATCH 0x01 9 | #define REG_ACT_LATCH 0x02 10 | #define REG_COND_SEL 0x03 11 | #define REG_COND_POL 0x04 12 | #define REG_CSR 0x05 13 | 14 | #define CSR_PLS (1 << 0) 15 | #define CSR_CT (1 << 1) 16 | #define CSR_POR (1 << 3) 17 | #define CSR_VCC (1 << 7) 18 | 19 | #define CMD_PIO_READ 0xF0 20 | #define CMD_CH_READ 0xF5 21 | #define CMD_CH_WRITE 0x5A 22 | #define CMD_WRITE_CS 0xCC 23 | #define CMD_RESET_AL 0xC3 24 | 25 | #define PWM_STEPS 127 26 | #define UINT8_T_MAX 0xFF 27 | 28 | uint8_t instance_count = 0; 29 | 30 | inline uint16_t reg_to_steps(uint8_t reg) { 31 | uint16_t v = reg * PWM_STEPS / UINT8_T_MAX; 32 | if (reg == 0) { 33 | v = 0; 34 | } else if (reg == UINT8_T_MAX) { 35 | v = PWM_STEPS; 36 | } 37 | return PWM_STEPS - v; 38 | } 39 | 40 | inline uint8_t steps_to_reg(uint8_t steps) { 41 | uint8_t v = steps * UINT8_T_MAX / PWM_STEPS; 42 | if (steps == PWM_STEPS) { 43 | v = UINT8_T_MAX; 44 | } else if (steps == 0) { 45 | v = 0; 46 | } 47 | return UINT8_T_MAX - v; 48 | } 49 | 50 | static void reg_write(uint8_t address, one_2408_pwm * d2408, uint8_t data) { 51 | switch (address) { 52 | case REG_OUT_LATCH: 53 | * d2408->timer_ccr = reg_to_steps(~data); 54 | break; 55 | case REG_CSR: 56 | d2408->reg_csr = data; 57 | break; 58 | default: 59 | break; 60 | } 61 | } 62 | 63 | static inline uint8_t reg_read(uint8_t address, one_2408_pwm * d2408) { 64 | uint8_t reg_data; 65 | switch (address) { 66 | case REG_OUT_LATCH: 67 | reg_data = ~steps_to_reg(* d2408->timer_ccr); 68 | break; 69 | case REG_PIO_LOGIC: 70 | case REG_ACT_LATCH: 71 | case REG_COND_SEL: 72 | case REG_COND_POL: 73 | reg_data = 0; 74 | break; 75 | case REG_CSR: 76 | reg_data = d2408->reg_csr; 77 | break; 78 | default: 79 | reg_data = 0xFF; 80 | break; 81 | } 82 | return reg_data; 83 | } 84 | 85 | static void pio_read(void * device) { 86 | union { 87 | uint16_t data_int16; 88 | uint8_t data_int8[2]; 89 | } crc = { 0 }; 90 | uint8_t reg_addr; 91 | one_2408_pwm * d2408 = (one_2408_pwm *) device; 92 | uint8_t i; 93 | uint8_t reg_data; 94 | 95 | reg_addr = one_read_byte(); 96 | one_read_byte(); 97 | 98 | crc.data_int16 = crc16(CMD_PIO_READ, crc.data_int16); 99 | crc.data_int16 = crc16(reg_addr, crc.data_int16); 100 | crc.data_int16 = crc16(0, crc.data_int16); 101 | 102 | for ( 103 | i = reg_addr - REG_OFFSET; 104 | i < REG_PAGE_LENGTH; 105 | i++ 106 | ) { 107 | reg_data = reg_read(i, d2408); 108 | one_write_byte(reg_data); 109 | crc.data_int16 = crc16(reg_data, crc.data_int16); 110 | } 111 | 112 | one_write_byte(~crc.data_int8[0]); 113 | one_write_byte(~crc.data_int8[1]); 114 | } 115 | 116 | static void write_cs_reg(void * device) { 117 | uint8_t reg_addr; 118 | one_2408_pwm * d2408 = (one_2408_pwm *) device; 119 | uint8_t data; 120 | 121 | reg_addr = one_read_byte(); 122 | one_read_byte(); 123 | 124 | if ( 125 | (reg_addr < 0x8B) || 126 | (reg_addr > 0x8D) 127 | ) { 128 | return; 129 | } 130 | 131 | while (1) { 132 | if (reg_addr > 0x8D) { 133 | return; 134 | } 135 | data = one_read_byte(); 136 | if (one_reset_flag) { 137 | return; 138 | } 139 | reg_write(reg_addr - REG_OFFSET, d2408, data); 140 | reg_addr++; 141 | } 142 | } 143 | 144 | static void channel_access_write(void * device) { 145 | one_2408_pwm * d2408 = (one_2408_pwm *) device; 146 | uint8_t address = REG_OUT_LATCH; 147 | uint8_t data; 148 | 149 | while (1) { 150 | data = one_read_byte(); 151 | 152 | if (one_reset_flag) { 153 | return; 154 | } 155 | 156 | if ((uint8_t) (~data) == one_read_byte()) { 157 | reg_write(address, d2408, data); 158 | } 159 | 160 | if (one_reset_flag) { 161 | return; 162 | } 163 | 164 | one_write_byte(0xAA); 165 | one_write_byte(data); 166 | 167 | address++; 168 | } 169 | } 170 | 171 | static void reset_activity_latch(void * device) { 172 | (void) device; 173 | one_write_byte(0xAA); 174 | } 175 | 176 | static void channel_access_read(void * device) { 177 | union { 178 | uint16_t data_int16; 179 | uint8_t data_int8[2]; 180 | } crc; 181 | uint8_t i; 182 | uint8_t data; 183 | one_2408_pwm * d2408 = (one_2408_pwm *) device; 184 | 185 | crc.data_int16 = crc16(CMD_CH_READ, 0); 186 | 187 | for (i = 0; i < 32; i++) { 188 | data = steps_to_reg(* (d2408->timer_ccr)); 189 | one_write_byte(data); 190 | crc.data_int16 = crc16(data, crc.data_int16); 191 | } 192 | 193 | one_write_byte(~crc.data_int8[0]); 194 | one_write_byte(~crc.data_int8[1]); 195 | } 196 | 197 | void one_2408_pwm_process(void * device) { 198 | uint8_t command = one_read_byte(); 199 | 200 | switch (command) { 201 | case CMD_PIO_READ: 202 | pio_read(device); 203 | break; 204 | case CMD_CH_READ: 205 | channel_access_read(device); 206 | break; 207 | case CMD_CH_WRITE: 208 | channel_access_write(device); 209 | break; 210 | case CMD_WRITE_CS: 211 | write_cs_reg(device); 212 | break; 213 | case CMD_RESET_AL: 214 | reset_activity_latch(device); 215 | break; 216 | default: 217 | break; 218 | } 219 | } 220 | 221 | static void pwm_timer_setup() { 222 | TA1CCR0 = PWM_STEPS; 223 | 224 | TA1CCTL1 = OUTMOD_6; 225 | TA1CCTL2 = OUTMOD_6; 226 | 227 | TA1CCR1 = PWM_STEPS; 228 | TA1CCR2 = PWM_STEPS; 229 | 230 | TA1CTL = TASSEL_2 + MC_3; 231 | } 232 | 233 | void one_2408_pwm_init(void * device) { 234 | if (instance_count == 0) { 235 | pwm_timer_setup(); 236 | } 237 | 238 | instance_count++; 239 | 240 | if (instance_count > 2) { 241 | return; 242 | } 243 | 244 | one_device * d; 245 | one_2408_pwm * d2408_pwm; 246 | 247 | d = (one_device *) device; 248 | d2408_pwm = (one_2408_pwm *) d->device; 249 | 250 | * (d2408_pwm->port_base + OFS_DIR) |= d2408_pwm->out_bit; 251 | * (d2408_pwm->port_base + OFS_SEL) |= d2408_pwm->out_bit; 252 | 253 | switch(instance_count) { 254 | case 1: 255 | d2408_pwm->timer_ccr = &TA1CCR1; 256 | break; 257 | case 2: 258 | d2408_pwm->timer_ccr = &TA1CCR2; 259 | default: 260 | break; 261 | } 262 | 263 | d->process = &one_2408_pwm_process; 264 | d->condition = &one_condition_dummy; 265 | 266 | d2408_pwm->reg_csr |= CSR_VCC | CSR_POR; 267 | } 268 | -------------------------------------------------------------------------------- /one-slave/devices/one-2408.c: -------------------------------------------------------------------------------- 1 | #include "one-2408.h" 2 | #include "one-slave.h" 3 | 4 | #define OR_REDUCE(a) (a != 0) 5 | #define AND_REDUCE(a) (a == ~(a & 0)) 6 | 7 | #define REG_OFFSET 0x88 8 | #define REG_PAGE_LENGTH 0x08 9 | 10 | // PIO logic state 11 | #define REG_PIO_LOGIC 0x00 12 | // PIO output latch 13 | #define REG_OUT_LATCH 0x01 14 | // PIO activity latch 15 | #define REG_ACT_LATCH 0x02 16 | // Conditional search channel selection mask 17 | #define REG_COND_SEL 0x03 18 | // Conditional search channel polarity selection 19 | #define REG_COND_POL 0x04 20 | // Control/status register 21 | #define REG_CSR 0x05 22 | 23 | // Control/status register 24 | // Pin/activity latch select 25 | #define CSR_PLS (1 << 0) 26 | // Conditional search logical term 27 | #define CSR_CT (1 << 1) 28 | // Power-on reset latch 29 | #define CSR_POR (1 << 3) 30 | // Vcc status 31 | #define CSR_VCC (1 << 7) 32 | 33 | #define CMD_PIO_READ 0xF0 34 | #define CMD_CH_READ 0xF5 35 | #define CMD_CH_WRITE 0x5A 36 | #define CMD_WRITE_CS 0xCC 37 | #define CMD_RESET_AL 0xC3 38 | 39 | void reg_write(uint8_t address, one_2408 * d2408, uint8_t data) { 40 | switch (address) { 41 | case REG_OUT_LATCH: 42 | * (d2408->port_base + OFS_OUT) = ~data; 43 | break; 44 | case REG_COND_SEL: 45 | d2408->reg_cond_mask = data; 46 | break; 47 | case REG_COND_POL: 48 | * (d2408->port_base + OFS_DIR) = data; 49 | break; 50 | case REG_ACT_LATCH: 51 | * (d2408->port_base + OFS_IFG) = data; 52 | break; 53 | case REG_CSR: 54 | d2408->reg_csr = data; 55 | break; 56 | default: 57 | break; 58 | } 59 | } 60 | 61 | inline uint8_t reg_read(uint8_t address, one_2408 * d2408) { 62 | uint8_t reg_data; 63 | switch (address) { 64 | case REG_PIO_LOGIC: 65 | reg_data = * (d2408->port_base + OFS_IN); 66 | break; 67 | case REG_OUT_LATCH: 68 | reg_data = ~(* (d2408->port_base + OFS_OUT)); 69 | break; 70 | case REG_ACT_LATCH: 71 | reg_data = * (d2408->port_base + OFS_IFG); 72 | break; 73 | case REG_COND_SEL: 74 | reg_data = d2408->reg_cond_mask; 75 | break; 76 | case REG_COND_POL: 77 | reg_data = * (d2408->port_base + OFS_DIR); 78 | break; 79 | case REG_CSR: 80 | reg_data = d2408->reg_csr; 81 | break; 82 | default: 83 | reg_data = 0xFF; 84 | break; 85 | } 86 | return reg_data; 87 | } 88 | 89 | void pio_read(void * device) { 90 | union { 91 | uint16_t data_int16; 92 | uint8_t data_int8[2]; 93 | } crc = { 0 }; 94 | uint8_t reg_addr; 95 | one_2408 * d2408 = (one_2408 *) device; 96 | uint8_t i; 97 | uint8_t reg_data; 98 | 99 | reg_addr = one_read_byte(); 100 | one_read_byte(); 101 | 102 | crc.data_int16 = crc16(CMD_PIO_READ, crc.data_int16); 103 | crc.data_int16 = crc16(reg_addr, crc.data_int16); 104 | crc.data_int16 = crc16(0, crc.data_int16); 105 | 106 | for ( 107 | i = reg_addr - REG_OFFSET; 108 | i < REG_PAGE_LENGTH; 109 | i++ 110 | ) { 111 | reg_data = reg_read(i, d2408); 112 | one_write_byte(reg_data); 113 | crc.data_int16 = crc16(reg_data, crc.data_int16); 114 | } 115 | 116 | one_write_byte(~crc.data_int8[0]); 117 | one_write_byte(~crc.data_int8[1]); 118 | } 119 | 120 | void write_cs_reg(void * device) { 121 | uint8_t reg_addr; 122 | one_2408 * d2408 = (one_2408 *) device; 123 | uint8_t data; 124 | 125 | reg_addr = one_read_byte(); 126 | one_read_byte(); 127 | 128 | if ( 129 | (reg_addr < 0x8B) || 130 | (reg_addr > 0x8D) 131 | ) { 132 | return; 133 | } 134 | 135 | while (1) { 136 | if (reg_addr > 0x8D) { 137 | return; 138 | } 139 | data = one_read_byte(); 140 | if (one_reset_flag) { 141 | return; 142 | } 143 | reg_write(reg_addr - REG_OFFSET, d2408, data); 144 | reg_addr++; 145 | } 146 | } 147 | 148 | void channel_access_write(void * device) { 149 | one_2408 * d2408 = (one_2408 *) device; 150 | uint8_t address = REG_OUT_LATCH; 151 | uint8_t data; 152 | 153 | while (1) { 154 | data = one_read_byte(); 155 | 156 | if (one_reset_flag) { 157 | return; 158 | } 159 | 160 | if ((uint8_t) (~data) == one_read_byte()) { 161 | reg_write(address, d2408, data); 162 | } 163 | 164 | if (one_reset_flag) { 165 | return; 166 | } 167 | 168 | one_write_byte(0xAA); 169 | one_write_byte(data); 170 | 171 | address++; 172 | } 173 | } 174 | 175 | void reset_activity_latch(void * device) { 176 | one_2408 * d2408 = (one_2408 *) device; 177 | 178 | reg_write(REG_ACT_LATCH, d2408, 0); 179 | 180 | one_write_byte(0xAA); 181 | } 182 | 183 | void channel_access_read(void * device) { 184 | union { 185 | uint16_t data_int16; 186 | uint8_t data_int8[2]; 187 | } crc; 188 | uint8_t i; 189 | uint8_t data; 190 | one_2408 * d2408 = (one_2408 *) device; 191 | 192 | crc.data_int16 = crc16(CMD_CH_READ, 0); 193 | 194 | for (i = 0; i < 32; i++) { 195 | data = * (d2408->port_base + OFS_IN); 196 | one_write_byte(data); 197 | crc.data_int16 = crc16(data, crc.data_int16); 198 | } 199 | 200 | one_write_byte(~crc.data_int8[0]); 201 | one_write_byte(~crc.data_int8[1]); 202 | } 203 | 204 | void one_2408_process(void * device) { 205 | uint8_t command = one_read_byte(); 206 | 207 | switch (command) { 208 | case CMD_PIO_READ: 209 | pio_read(device); 210 | break; 211 | case CMD_CH_READ: 212 | channel_access_read(device); 213 | break; 214 | case CMD_CH_WRITE: 215 | channel_access_write(device); 216 | break; 217 | case CMD_WRITE_CS: 218 | write_cs_reg(device); 219 | break; 220 | case CMD_RESET_AL: 221 | reset_activity_latch(device); 222 | break; 223 | default: 224 | break; 225 | } 226 | } 227 | 228 | uint8_t one_2408_condition(void * device) { 229 | one_2408 * d2408 = (one_2408 *) device; 230 | uint8_t cond_data; 231 | 232 | cond_data = 233 | d2408->reg_csr & CSR_PLS ? 234 | * (d2408->port_base + OFS_IFG): 235 | * (d2408->port_base + OFS_IN); 236 | 237 | cond_data &= d2408->reg_cond_mask; 238 | 239 | return 240 | d2408->reg_csr & CSR_CT ? 241 | AND_REDUCE(cond_data) : 242 | OR_REDUCE(cond_data); 243 | } 244 | 245 | void one_2408_init(void * device) { 246 | one_device * d; 247 | one_2408 * d2408; 248 | 249 | d = (one_device *) device; 250 | d2408 = (one_2408 *) d->device; 251 | 252 | * (d2408->port_base + OFS_OUT) = 0; 253 | * (d2408->port_base + OFS_DIR) = ONE_2408_DEF_PDIR; 254 | * (d2408->port_base + OFS_IFG) = 0; 255 | 256 | d->process = &one_2408_process; 257 | d->condition = &one_2408_condition; 258 | d2408->reg_cond_mask = 0; 259 | d2408->reg_cond_pol = 0; 260 | d2408->reg_csr |= CSR_VCC | CSR_POR; 261 | } 262 | -------------------------------------------------------------------------------- /one-slave/one-slave.c: -------------------------------------------------------------------------------- 1 | #include "one-slave.h" 2 | 3 | #define P6(A, B, C, D, E, F) A ## B ## C ## D ## E ## F 4 | #define E6(A, B, C, D, E, F) P6(A, B, C, D, E, F) 5 | 6 | #define P3(A, B, C) A ## B ## C 7 | #define E3(A, B, C) P3(A, B, C) 8 | 9 | #define P2(A, B) A ## B 10 | #define E2(A, B) P2(A, B) 11 | 12 | #define P1(A) A 13 | #define E1(A) P1(A) 14 | 15 | #define ONE_PDIR E3(P, ONE_PORT, DIR) 16 | #ifdef OUT 17 | #undef OUT 18 | #endif 19 | #define ONE_POUT E3(P, ONE_PORT, OUT) 20 | #define ONE_PIN E3(P, ONE_PORT, IN) 21 | #define ONE_IE E3(P, ONE_PORT, IE) 22 | #define ONE_IV E3(P, ONE_PORT, IV) 23 | #define ONE_IES E3(P, ONE_PORT, IES) 24 | #define ONE_IFG E3(P, ONE_PORT, IFG) 25 | #define ONE_REN E3(P, ONE_PORT, REN) 26 | 27 | #define ONE_BIT_IN E2(BIT, ONE_B_IN) 28 | #define ONE_BIT_OUT E2(BIT, ONE_B_OUT) 29 | 30 | #define ONE_IV_IFG E6(P, ONE_PORT, IV_P, ONE_PORT, IFG, ONE_B_IN) 31 | 32 | #define ONE_VECTOR E3(PORT, ONE_PORT, _VECTOR) 33 | 34 | #define DELAY(US, CLOCK_FREQ) (CLOCK_FREQ / 1'000'000 * US) 35 | 36 | #define TIME_RESET_MIN 480 37 | #define TIME_PRESENCE 130 38 | #define TIME_PRESENCE_DELAY 15 39 | #define TIME_TS_VALUE 30 40 | #define TIME_TS_OUT 25 41 | 42 | #define COMMAND_ROM_SEARCH 0xF0 43 | #define COMMAND_ROM_SEARCH_COND 0xEC 44 | #define COMMAND_ROM_READ 0x33 45 | #define COMMAND_ROM_MATCH 0x55 46 | #define COMMAND_ROM_SKIP 0xCC 47 | 48 | #define OUTPUT_ASSERT (ONE_POUT |= ONE_BIT_OUT) 49 | #define OUTPUT_DEASSERT (ONE_POUT &= ~ONE_BIT_OUT) 50 | 51 | #define EDGE_FALL (ONE_IES |= ONE_BIT_IN) 52 | #define EDGE_RISE (ONE_IES &= ~ONE_BIT_IN) 53 | 54 | #define INT_ENABLE (ONE_IE |= ONE_BIT_IN) 55 | #define INT_DISABLE (ONE_IE &= ~ONE_BIT_IN) 56 | 57 | #define TIMER_DIV 1 58 | #define TIMER_MUL 2 59 | #define DELAY_US(us) ((us / TIMER_DIV) * TIMER_MUL) 60 | 61 | #define MAX_DEVICE_COUNT 4 62 | 63 | #define MASK_LOWER_4 0x0F 64 | #define MASK_HIGH_4 0xF0 65 | 66 | #define LSB_EXTEND(a) ((a & 0x01) ? (~(0 & a)) : 0) 67 | 68 | typedef enum { 69 | state_idle, 70 | state_waiting_for_reset, 71 | state_search_rom, 72 | state_match_rom, 73 | state_device_selected 74 | } one_state_type; 75 | 76 | one_state_type state; 77 | 78 | uint8_t search_rom_cond = 0; 79 | uint8_t selected_device; 80 | uint8_t reset_lpm_exit = 0; 81 | uint8_t one_reset_flag = 0; 82 | 83 | one_device * device; 84 | uint8_t device_count; 85 | 86 | union { 87 | uint8_t data_int8[32]; 88 | uint16_t data_int16[16]; 89 | } device_addr = { 0 }; 90 | 91 | void clock_system_setup() { 92 | /* 93 | * Basic clock system+ setup 94 | * 95 | * MCLK = 16 MHz 96 | * SMCLK = 2 MHz 97 | */ 98 | DCOCTL = CALDCO_16MHZ; 99 | BCSCTL1 = CALBC1_16MHZ; 100 | 101 | BCSCTL2 |= DIVS_3; 102 | } 103 | 104 | inline void timer_start() { 105 | TA0R = 0; 106 | // Upmode 107 | TA0CTL |= MC_2; 108 | } 109 | 110 | inline void timer_stop() { 111 | TA0CTL &= ~(BIT4 | BIT5); 112 | } 113 | 114 | void timer_init() { 115 | // SMCLK source 116 | // Enable interrupt 117 | // Upmode 118 | // Clear timer 119 | TA0CTL = TACLR + MC_0 + TAIE + TASSEL_2; 120 | TA0CCTL0 |= CCIE; 121 | TA0CCTL1 |= CCIE; 122 | TA0CCR1 = DELAY_US(TIME_RESET_MIN); 123 | } 124 | 125 | /* 126 | * Copyright: https://github.com/pbrook/arduino-onewire/ 127 | */ 128 | uint8_t crc8(uint8_t * buffer, uint8_t size) { 129 | uint8_t crc = 0; 130 | uint8_t byte, i, m; 131 | while (size--) { 132 | byte = * buffer++; 133 | for (i = 8; i; i--) { 134 | m = (crc ^ byte) & 0x01; 135 | crc >>= 1; 136 | crc ^= m ? 0x8C : 0; 137 | byte >>= 1; 138 | } 139 | } 140 | return crc; 141 | } 142 | 143 | /* 144 | * Copyright: https://github.com/pbrook/arduino-onewire/ 145 | */ 146 | uint16_t crc16(uint8_t input, uint16_t seed) { 147 | static const uint8_t oddparity[16] = { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 }; 148 | uint16_t cdata = input; 149 | cdata = (cdata ^ (seed & 0xff)) & 0xff; 150 | seed >>= 8; 151 | if (oddparity[cdata & 0x0F] ^ oddparity[cdata >> 4]) { 152 | seed ^= 0xC001; 153 | } 154 | cdata <<= 6; 155 | seed ^= cdata; 156 | cdata <<= 1; 157 | seed ^= cdata; 158 | return seed; 159 | } 160 | 161 | void one_init(one_device * d, const uint8_t count) { 162 | if (count > 4) { 163 | return; 164 | } 165 | // 166 | clock_system_setup(); 167 | timer_init(); 168 | state = state_idle; 169 | // GPIO setup 170 | ONE_POUT &= ~(ONE_BIT_IN | ONE_BIT_OUT); 171 | ONE_PDIR |= ONE_BIT_OUT; 172 | ONE_PDIR &= ~ONE_BIT_IN; 173 | ONE_IE |= ONE_BIT_IN; 174 | EDGE_FALL; 175 | // Devices setup 176 | device = d; 177 | device_count = count; 178 | uint8_t i = count - 1; 179 | uint8_t crc_array[7]; 180 | do { 181 | // Calculate CRC8 182 | memcpy(&crc_array, (void *) &device[i].rom, 7); 183 | device[i].rom |= (uint64_t) crc8((uint8_t *) &crc_array, 7) << 56; 184 | device[i].init(&device[i]); 185 | } while (i--); 186 | // Fill device address array 187 | uint8_t device_index; 188 | uint8_t current; 189 | for (i = 0; i < 64; i++) { 190 | for (device_index = 0; device_index < device_count; device_index++) { 191 | current = device[device_index].rom & ((uint64_t)1 << i) ? 1 : 0; 192 | if (i & 0x01) { 193 | device_addr.data_int8[i >> 1] |= current << (device_index + 4); 194 | } else { 195 | device_addr.data_int8[i >> 1] |= current << (device_index); 196 | } 197 | } 198 | } 199 | } 200 | 201 | void process_command(uint8_t command) { 202 | switch (command) { 203 | case COMMAND_ROM_SEARCH_COND: 204 | search_rom_cond = 1; 205 | case COMMAND_ROM_SEARCH: 206 | INT_ENABLE; 207 | state = state_search_rom; 208 | break; 209 | case COMMAND_ROM_MATCH: 210 | state = state_match_rom; 211 | break; 212 | default: 213 | state = state_idle; 214 | break; 215 | } 216 | } 217 | 218 | void process_state_idle() { 219 | LPM1; 220 | TA0CCR0 = 0xFFFF; 221 | timer_start(); 222 | reset_lpm_exit = 1; 223 | // 224 | LPM1; 225 | } 226 | 227 | uint8_t timeslot_read() { 228 | LPM1; 229 | TA0CCR0 = DELAY_US(TIME_TS_VALUE); 230 | timer_start(); 231 | LPM1; 232 | return ((ONE_PIN & ONE_BIT_IN) > 0); 233 | } 234 | 235 | void timeslot_write(uint8_t bit) { 236 | LPM1; 237 | TA0CCR0 = DELAY_US(TIME_TS_OUT); 238 | if (!bit) { 239 | OUTPUT_ASSERT; 240 | } 241 | timer_start(); 242 | LPM1; 243 | OUTPUT_DEASSERT; 244 | } 245 | 246 | void one_write_byte(uint8_t data) { 247 | uint8_t data_bits_processed = 0; 248 | EDGE_FALL; 249 | TA0CCR0 = 0xFFFF; 250 | while ((data_bits_processed < 8) && !one_reset_flag) { 251 | timeslot_write(data & (1 << data_bits_processed)); 252 | data_bits_processed++; 253 | } 254 | timer_stop(); 255 | } 256 | 257 | uint8_t one_read_byte() { 258 | uint8_t data = 0; 259 | uint8_t data_bits_processed = 0; 260 | EDGE_FALL; 261 | TA0CCR0 = 0xFFFF; 262 | while ((data_bits_processed < 8) && !one_reset_flag) { 263 | data |= (timeslot_read()) << data_bits_processed; 264 | data_bits_processed++; 265 | } 266 | timer_stop(); 267 | return data; 268 | } 269 | 270 | void process_state_waiting_for_reset() { 271 | one_reset_flag = 0; 272 | while ((ONE_BIT_IN & ONE_PIN) == 0); 273 | // Send presence response 274 | TA0CCR0 = DELAY_US(TIME_PRESENCE_DELAY); 275 | timer_start(); 276 | LPM1; 277 | // 278 | TA0CCR0 = DELAY_US(TIME_PRESENCE); 279 | timer_start(); 280 | // 281 | INT_DISABLE; 282 | OUTPUT_ASSERT; 283 | // 284 | LPM1; 285 | // 286 | OUTPUT_DEASSERT; 287 | INT_ENABLE; 288 | timer_stop(); 289 | process_command(one_read_byte()); 290 | } 291 | 292 | void process_state_search_rom() { 293 | uint8_t mask = (MASK_HIGH_4 >> (4 - device_count)) & MASK_LOWER_4; 294 | union { 295 | uint8_t data_int8[32]; 296 | uint16_t data_int16[16]; 297 | } search_addr; 298 | uint8_t index; 299 | uint8_t direction; 300 | uint8_t addr_bits; 301 | 302 | for (index = 0; index < 16; index++) { 303 | search_addr.data_int16[index] = device_addr.data_int16[index]; 304 | } 305 | 306 | if (search_rom_cond) { 307 | for (index = 0; index < device_count; index++) { 308 | mask |= ((!device[index].condition(device[index].device)) << index); 309 | } 310 | } 311 | 312 | if (mask == 0) { 313 | goto exit; 314 | } 315 | 316 | index = 0; 317 | 318 | while (!one_reset_flag) { 319 | addr_bits = 320 | (index & 0x01) ? 321 | search_addr.data_int8[index >> 1] >> 4 : 322 | search_addr.data_int8[index >> 1] & MASK_LOWER_4; 323 | 324 | addr_bits |= mask; 325 | timeslot_write(addr_bits == MASK_LOWER_4); 326 | timeslot_write(addr_bits == mask); 327 | 328 | direction = timeslot_read(); 329 | direction = LSB_EXTEND(direction); 330 | // direction: either 0xFF or 0x00 331 | // addr_bits: 0000 ABCD 332 | mask |= (addr_bits ^ direction) & MASK_LOWER_4; 333 | if ((mask == MASK_LOWER_4) || (index == 63)) { 334 | break; 335 | } 336 | index++; 337 | } 338 | 339 | exit: 340 | search_rom_cond = 0; 341 | state = state_idle; 342 | } 343 | 344 | void process_state_match_rom() { 345 | volatile union { 346 | uint64_t data_int64; 347 | uint8_t data_int8[8]; 348 | } address; 349 | uint8_t i; 350 | 351 | for (i = 0; i < 8; i++) { 352 | address.data_int8[i] = one_read_byte(); 353 | } 354 | 355 | for (i = 0; i < device_count; i++) { 356 | if (device[i].rom == address.data_int64) { 357 | state = state_device_selected; 358 | selected_device = i; 359 | return; 360 | } 361 | } 362 | 363 | state = state_idle; 364 | } 365 | 366 | void process_state_device_selected() { 367 | void * device_data = device[selected_device].device; 368 | device[selected_device].process(device_data); 369 | state = state_idle; 370 | } 371 | 372 | void one_process_state() { 373 | switch (state) { 374 | case state_idle: 375 | process_state_idle(); 376 | break; 377 | case state_waiting_for_reset: 378 | process_state_waiting_for_reset(); 379 | break; 380 | case state_search_rom: 381 | process_state_search_rom(); 382 | break; 383 | case state_match_rom: 384 | process_state_match_rom(); 385 | break; 386 | case state_device_selected: 387 | process_state_device_selected(); 388 | break; 389 | default: 390 | break; 391 | } 392 | if (one_reset_flag) { 393 | state = state_waiting_for_reset; 394 | } 395 | } 396 | 397 | uint8_t one_condition_dummy(void * device) { 398 | return 0; 399 | } 400 | 401 | #pragma vector=ONE_VECTOR 402 | __interrupt void one_interrupt() { 403 | if (ONE_IFG & ONE_BIT_IN) { 404 | ONE_IFG &= ~ONE_BIT_IN; 405 | LPM1_EXIT; 406 | } 407 | } 408 | 409 | #pragma vector=TIMER0_A0_VECTOR 410 | __interrupt void one_timer_timeslot() { 411 | LPM1_EXIT; 412 | } 413 | 414 | #pragma vector=TIMER0_A1_VECTOR 415 | __interrupt void one_timer_reset() { 416 | if (TA0IV == TA0IV_TACCR1) { 417 | timer_stop(); 418 | one_reset_flag = (ONE_PIN & ONE_BIT_IN) == 0; 419 | if (reset_lpm_exit || one_reset_flag) { 420 | reset_lpm_exit = 0; 421 | LPM1_EXIT; 422 | } 423 | break; 424 | } else { 425 | timer_stop(); 426 | break; 427 | } 428 | } 429 | -------------------------------------------------------------------------------- /hardware/main.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | To MSP430 7 | LD1117D33TR 8 | 9 | u 10 | 0 11 | 1 12 | u 13 | 0 14 | 1 15 | 16 | GND 17 | GND 18 | +5V 19 | +5V 20 | +3V3 21 | 39k 22 | 68k 23 | GND 24 | BSS123 25 | 10k 26 | 4.7k 27 | GNDGND 28 | JP1 29 | 1 30 | 2 31 | 3 32 | IC1 33 | ADJ 34 | INOUT 35 | 36 | 2 37 | C 38 | 1 39 | C 40 | 41 | R1 42 | R2 43 | Q1 44 | R3 45 | R4 46 | GND 47 | 49 | 51 | 52 | GND 53 | DATA 54 | +5V 55 | 57 | 59 | 60 | +3V3 61 | 63 | 65 | 66 | MSP430_IN 67 | 69 | 71 | 72 | MSP430_OUT 73 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 108 | 109 | 111 | 112 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 131 | 132 | 133 | 135 | 137 | 138 | 140 | 141 | 143 | 145 | 147 | 149 | 151 | 153 | 155 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 184 | 185 | 187 | 190 | 191 | 193 | 194 | 195 | 196 | 197 | 199 | 200 | 202 | 205 | 207 | 209 | 210 | 212 | 215 | 217 | 218 | 220 | 223 | 224 | 226 | 228 | 231 | 233 | 235 | 236 | 238 | 241 | 243 | 244 | --------------------------------------------------------------------------------