# Module 3: Data Tables

> Coils, discrete inputs, input registers, and holding registers — the four primitives.

**Phase:** Foundations  
**Estimated time:** 7 min  
**Release status:** Published  
**Content version:** 1.0.0  
**Source:** https://learnmodbus.studioseventeen.io/lesson/data-tables

## What you'll be able to do
- Pick the right Modbus data table for a given device signal.
- Explain why a vendor map of 'inputs' rarely means 'discrete inputs'.
- Use the table to predict which function codes are legal.

## Three things people get wrong
1. **Assuming 'input' means discrete input.** Vendors use 'input' for analog input registers (table 3) far more often than for discrete inputs (table 2).
2. **Writing to a register because FC 06 is 'allowed'.** Allowed at the protocol layer is not the same as safe at the device layer. Check the map's R/W column.
3. **Mixing tables across one transaction.** Each read function code targets exactly one table. Plan separate reads for coils, registers, and inputs.

## From the field
**When a holding register killed a setpoint**

An operator's HMI cycled FC 16 to 'refresh' a value it had just read. The PLC accepted the writes, overwriting a recipe parameter someone had nudged manually that morning. Reads and writes use the same table — that's the whole point, and it bites if you forget it.

## References
- [Modbus Application Protocol V1.1b3](https://www.modbus.org/file/secure/modbusprotocolspecification.pdf) — Data model — section 4.3

## Lesson

# Module 3 Lesson: Data Tables
## Learner Outcome

By the end of this module, learners can distinguish the four primary Modbus logical data tables, choose the likely table and access pattern for common field values, and explain why documentation prefixes are not wire-level fields.

## Key Concepts

- Coils are 1-bit read/write items.
- Discrete inputs are 1-bit read-only items.
- Input registers are 16-bit read-only words.
- Holding registers are 16-bit words commonly used for read/write values, though many devices also expose read-only measurements there.
- The function code selects the logical table; the PDU address selects an offset inside that table.
- Prefixes such as `0xxxx`, `1xxxx`, `3xxxx`, and `4xxxx` are documentation conventions, not bytes sent on the wire.
- Real device maps can bend the clean teaching model; vendor-specific mapping must be labeled as product behavior.

## Key Terms

- Coil: a single-bit read/write logical point often used for discrete commands or states.
- Discrete input: a single-bit read-only logical point.
- Input register: a 16-bit read-only register.
- Holding register: a 16-bit register that is commonly read and may be writable depending on the device map.
- Logical table: the Modbus data area selected by function code and source-map context.
- Access: whether the point is read-only, write-capable, reserved, or otherwise constrained by the device.

## Source-Grounded Explanation

### The Four Logical Tables

Modbus defines a logical data model with four primary table types:

| Table | Object Type | Typical Access | Legacy Prefix | Common Read Function | Common Write Function |
|---|---|---|---|---:|---:|
| Coils | 1-bit | Read/write | `0xxxx` | `01` | `05`, `15` |
| Discrete inputs | 1-bit | Read-only | `1xxxx` | `02` | Not writable |
| Input registers | 16-bit word | Read-only | `3xxxx` | `04` | Not writable |
| Holding registers | 16-bit word | Read/write table | `4xxxx` | `03` | `06`, `16` |

Advanced holding-register write-capable functions such as `22` and `23` are covered later with write-safety controls.

This table is the protocol mental model. It does not prove how a device stores data internally, whether a device implements every table, or whether a vendor exposes a measurement through input registers or holding registers.

### Function Code Selects The Table

The function code is what tells the server which logical table the request targets. The documentation prefix helps humans read the map, but it is not sent as a leading digit in the PDU.

For example, coil offset `0`, discrete input offset `0`, input register offset `0`, and holding register offset `0` can all exist without conflict because they live in different logical tables. The function code separates them:

| Request | Meaning |
|---|---|
| Function `01`, address `0` | Read coil offset `0` |
| Function `02`, address `0` | Read discrete input offset `0` |
| Function `04`, address `0` | Read input register offset `0` |
| Function `03`, address `0` | Read holding register offset `0` |

Address conversion details are taught in Module 5. In Module 3, the learner's job is to stop treating the prefix as a wire byte and start asking, "Which table does this row belong to, and which function reads or writes that table?"

### Field Practice Caveat

Real device maps often blur the neat categories:

- A measurement may appear in holding registers instead of input registers.
- A status may be exposed as a packed bitfield inside a holding register instead of as separate discrete inputs.
- A command may be a coil, a holding-register bit, an enum value, or a multi-step write workflow.
- A table may be documented as read/write even though specific rows are read-only or protected by local/remote mode.

Those are map and device behaviors, not changes to the core logical model. Label them as vendor-specific notes or synthetic fixture behavior until verified.

## Practical Example: Synthetic Four-Table Map

| Signal | Likely Table | Documented Reference | PDU Address Preview | Access | Type | Scale/Unit | Function To Read | Function To Write |
|---|---|---:|---:|---|---|---|---:|---:|
| Pump run command | Coil | `00001` | `0` | Read/write | Boolean | On/off | `01` | `05` or `15` |
| Door interlock closed | Discrete input | `10002` | `1` | Read-only | Boolean | Closed/open | `02` | Not writable |
| Supply temperature | Input register | `30010` | Module 5 preview | Read-only | U16 | `/10 deg C` | `04` | Not writable |
| Speed setpoint | Holding register | `40020` | Module 5 preview | Read/write in simulator | U16 | RPM | `03` | `06` or `16` |
| Alarm word | Holding register | `40030` | Module 5 preview | Read-only in this fixture | U16 bitfield | none | `03` | Not writable unless source proves it |

Source label: synthetic teaching fixture.

Worked distinction:

```text
Read coil offset 0:           function 01, address 0
Read discrete input offset 0: function 02, address 0
```

The numeric offset can match. The function code selects a different logical table.

## Common Pitfalls

- Treating `40001` as a literal numeric address sent on the wire.
- Choosing function `04` only because the value is an "input" to a software dashboard.
- Assuming every measurement must be in input registers.
- Trying to write to discrete inputs or input registers.
- Assuming every holding-register row is safe or allowed to write.
- Forgetting that status and alarms are often packed into 16-bit registers.
- Treating a vendor-specific map decision as a universal Modbus rule.

## Check-Your-Understanding

1. Which table is 1-bit and read/write?
2. Which table is 1-bit and read-only?
3. Which common function reads input registers?
4. What selects the table in the request: the legacy prefix or the function code?
5. Why can two values both use address offset `0` without conflicting?
6. What evidence is needed before writing to a holding-register row?

## Source Notes

- Official basis: Modbus Application Protocol Specification for logical data tables, PDU address fields, and common table/function-code mapping.
- Official citation targets: [official-citation-map.md](https://learnmodbus.studioseventeen.io/resource/official-citation-map) rows for four primary logical data tables, addressing model and zero-based PDU addresses, public function-code categories, and read function rows for coils, discrete inputs, input registers, and holding registers.
- Local course spine: `modbus-wiki.md` sections "Data Model", "Addressing", "Function Codes", and "Reading OEM Modbus Maps".
- Field note: real device maps can expose measurements, statuses, and commands in product-specific ways; vendor manuals govern named-device behavior.
- Synthetic basis: example map rows are course-authored teaching fixtures.

## Completion Checkpoint

Before moving on, learners should classify a point as coil, discrete input, input register, holding register, or needs verification, then explain what evidence they used. They should not infer a safe write just because a row appears near write-capable function codes.

## Reusable Assets

- [Four-table data model reference](https://learnmodbus.studioseventeen.io/resource/four-table-data-model-reference)
- [Data table classification worksheet](https://learnmodbus.studioseventeen.io/resource/data-table-classification-worksheet)
- [Module 3 lab](https://learnmodbus.studioseventeen.io/lesson/data-tables?page=lab-1)
- [Module 3 quiz](https://learnmodbus.studioseventeen.io/lesson/data-tables?page=quiz)

## Diagram source

```mermaid
flowchart TB
  M["Modbus Data Model"]
  M --> C["Coils<br/>1-bit · R/W"]
  M --> DI["Discrete Inputs<br/>1-bit · Read only"]
  M --> HR["Holding Registers<br/>16-bit · R/W"]
  M --> IR["Input Registers<br/>16-bit · Read only"]
```

## Labs

### Lab 1

# Lab 4: Data Table Classification
## Learner Outcome

Learners classify common field signals into likely Modbus logical tables, identify read/write access expectations, choose likely read/write functions, and record source questions before integration.

## Prerequisites

- Module 1 client/server mental model.
- Module 2 PDU/ADU and response-shape basics.
- Module 3 lesson or equivalent introduction to coils, discrete inputs, input registers, and holding registers.
- [Four-table data model reference](https://learnmodbus.studioseventeen.io/resource/four-table-data-model-reference)
- [Data table classification worksheet](https://learnmodbus.studioseventeen.io/resource/data-table-classification-worksheet)

## Safety And Scope

This is a no-hardware classification lab. Do not connect to devices or write to equipment. Write-capable examples are source-review prompts only.

## Scenario

A synthetic training controller exposes a small map for a pump skid. Learners must classify the signals before any polling or writing occurs.

Source label: synthetic teaching fixture.

| Signal | Source Wording | Learner Task |
|---|---|---|
| Pump run command | `00001`, R/W, Boolean | Identify likely coil table and read/write functions. |
| Door interlock closed | `10002`, R, Boolean | Identify likely discrete-input table and read-only access. |
| Supply temperature | `30010`, R, U16, `/10 deg C` | Identify likely input-register table and read function. |
| Speed setpoint | `40020`, R/W, U16, RPM | Identify likely holding-register table and write-safety questions. |
| Alarm word | `40030`, R, U16 bits | Identify holding-register bitfield and do not assume write access. |
| Line voltage | Source says only `Offset 9`, U16, `/10 V` | Mark table/function/address convention as unresolved. |

## Procedure

1. For each signal, choose the likely logical table.
2. Record the common read function.
3. Record the write function only when the table and source access allow it.
4. Mark any source questions: table, access, address convention, data type, scale/unit, state/validity, or safety requirement.
5. Explain why the same offset number can appear in more than one table.
6. Identify which rows are unsafe or unsupported to write.

## Answer Key

| Signal | Expected Classification |
|---|---|
| Pump run command | Coil; read with `01`; write with `05` or `15` only in approved simulator or reviewed device context. |
| Door interlock closed | Discrete input; read with `02`; not writable. |
| Supply temperature | Input register; read with `04`; not writable. |
| Speed setpoint | Holding register; read with `03`; possible write with `06` or `16` only after write-safety review. |
| Alarm word | Holding register bitfield; read with `03`; do not write unless source proves access and safety. |
| Line voltage | Needs verification; source row lacks table/function/address convention. |

## Expected Observations

- Discrete inputs and input registers are read-only from the Modbus data-model view used in this course.
- Coils and holding registers may be write-capable, but access and safety still depend on the source map and reviewed device context.
- The same numeric offset can appear in more than one logical table; the table/function context is part of the address evidence.
- Weak source rows should produce "needs verification" instead of a guessed function code.

## Troubleshooting Notes

- If learners classify every number as a holding register, redirect them to the signal type, access direction, and read function.
- If a row lacks table/function/address convention, mark it unresolved instead of forcing a request.
- If a write-capable table appears, require a write-safety stop before any real command is considered.
- If the value looks wrong but the table is uncertain, test table/function selection before scale, byte order, or word order.

## Check Questions

1. Which examples are read-only by logical table?
2. Which examples are write-capable by table but still require safety review?
3. Why is `Offset 9` incomplete documentation?
4. Why does a holding register not automatically mean "safe to write"?
5. What selects the logical table in the actual request?

## Instructor Notes

- Keep address-base math light. Module 5 handles conversion and off-by-one troubleshooting.
- Accept "likely table" only when the source row has enough evidence; otherwise require "needs verification."
- Use the alarm word to preview Module 8 bitfields.
- Use the speed setpoint to preview Module 15 write safety.

## Source Notes

- Official protocol basis: Modbus Application Protocol Specification for logical table model and function-code mapping.
- Synthetic basis: all scenario rows are course-authored fixtures.
- Field note: real vendor maps may expose measurements and status through product-specific table choices; do not generalize those choices without a named source.

## Knowledge check

# Module 3 Quiz: Data Tables
## Questions

1. Which Modbus table is 1-bit and commonly read/write?
   A. Coils
   B. Discrete inputs
   C. Input registers
   D. Holding registers

2. Which table is 1-bit and read-only?
   A. Coils
   B. Discrete inputs
   C. Input registers
   D. Holding registers

3. Which common function reads input registers?
   A. `01`
   B. `02`
   C. `03`
   D. `04`

4. A manual shows `40020`. What selects the holding-register table in the actual request?
   A. The ASCII character `4` sent before the address.
   B. The function code.
   C. The TCP port.
   D. The scale factor.

5. A device map lists an alarm word as `40030`, R, U16 bits. What is the safest interpretation?
   A. It is a holding-register bitfield that should be read and decoded; do not write unless the source proves write access and safety.
   B. It is a discrete input because alarms are binary.
   C. It must be writable because it starts with `4`.
   D. It is not Modbus.

6. A row says only `Offset 9`, U16, `/10 V`. What should the learner do?
   A. Assume holding register function `03`.
   B. Mark table/function/address convention as unresolved.
   C. Write to it with function `06`.
   D. Treat it as a coil.

7. Why can coil offset `0` and discrete input offset `0` both exist?
   A. They are selected by different function codes and logical tables.
   B. One is always TCP and one is always serial.
   C. Modbus forbids this.
   D. The PDU sends the `0xxxx` and `1xxxx` prefixes as bytes.

## Answer Key

1. A. Coils are 1-bit logical items with read/write functions.
2. B. Discrete inputs are 1-bit read-only items.
3. D. Function `04` reads input registers.
4. B. The function code selects the table; prefixes are documentation conventions.
5. A. A holding register can contain packed bits and may still be read-only by source permission.
6. B. Bare offsets need source evidence before choosing table/function/address convention.
7. A. The same offset can exist in different logical tables because the function code selects the table.

## Distractor Review Notes

| Question | Correct | Why The Distractors Are Wrong |
|---:|---|---|
| 1 | A | B is one-bit but read-only, and C/D are 16-bit register tables rather than the coil table. |
| 2 | B | A is commonly read/write, while C/D are register tables, not one-bit discrete input items. |
| 3 | D | A reads coils, B reads discrete inputs, and C reads holding registers rather than input registers. |
| 4 | B | A treats documentation notation as wire data, C is only a transport service number, and D is an engineering interpretation field. |
| 5 | A | B moves the point to a different table without source evidence, C assumes write permission from the prefix, and D rejects a normal Modbus modeling pattern. |
| 6 | B | A invents the table, C jumps to a write, and D changes the data type and table without evidence. |
| 7 | A | B invents a transport split, C denies valid separate table offsets, and D treats documentation prefixes as PDU bytes. |

## Instructor Notes

- Questions 4 and 7 reinforce prefixes-not-on-wire without turning Module 3 into the full addressing module.
- Questions 5 and 6 test source discipline and write-safety instincts.

## Source Notes

- Official citation targets: [official-citation-map.md](https://learnmodbus.studioseventeen.io/resource/official-citation-map) rows for four primary logical data tables, addressing model and zero-based PDU addresses, public function-code categories, and read function rows for coils, discrete inputs, input registers, and holding registers.
- Vendor-map meaning, access, and bit labels remain source-specific rather than official protocol behavior.

---
_Learn Modbus · learnmodbus.studioseventeen.io · Module 3/16 · v1.0.0 · Exported for offline / agent use._
