diff --git a/.metadata/sysconfig/.meta/ai.component.js b/.metadata/sysconfig/.meta/ai.component.js index 21eace6..eb589ab 100644 --- a/.metadata/sysconfig/.meta/ai.component.js +++ b/.metadata/sysconfig/.meta/ai.component.js @@ -2,7 +2,7 @@ const additionalInstructions = ` CRITICAL WORKFLOW - ALWAYS FOLLOW: CRITICAL RULE: Before calling addModuleInstances for ANY block: -1. MUST call getAIContext first to read documentation +1. Must read Agents.md and read the docs_ai for the blocks which will be used 2. NO EXCEPTIONS - even if you think you know the block 3. "When changing a module instance's $name configurable, the moduleInstanceId automatically updates to match the new name, so always use getModuleInstances() after renaming to retrieve the updated instance IDs before making connections or further modifications." 4. If you skip this step, acknowledge your mistake immediately diff --git a/.metadata/sysconfig/.meta/pru_blocks/application_specific/crc_block.syscfg.js b/.metadata/sysconfig/.meta/pru_blocks/application_specific/crc_block.syscfg.js index de0dd4b..a269fb0 100644 --- a/.metadata/sysconfig/.meta/pru_blocks/application_specific/crc_block.syscfg.js +++ b/.metadata/sysconfig/.meta/pru_blocks/application_specific/crc_block.syscfg.js @@ -177,90 +177,11 @@ function getMacro(pruInstructionMacro, opCode) return macroBody; } -function getAIContext(){ - return getLongDescription() + ` -## How to Configure (For AI/Scripting) -This section describes how to programmatically configure the CRC block in a .syscfg file. - -### Adding a CRC Instance - -\`\`\`javascript -const crc_block = scripting.addModule("/pru_blocks/application_specific/crc_block", {}, false); -const crc1 = crc_block.addInstance(); -\`\`\` - -### Configuration Parameters - -| Parameter | Type | Valid Values | Default | Description | -|-----------|------|--------------|---------|-------------| -| opCode | String | "m_calculate_crc8", "m_calculate_crc16", "m_calculate_crc32" | "m_calculate_crc8" | CRC algorithm type | -| crcPolynomial | Hex | Depends on CRC type | 0x07 | CRC polynomial (generator) | -| output1Size | String | "1", "2", "4" | "1" | Output size in bytes | - -### Valid CRC Types and Polynomials - -| CRC Type | Default Polynomial | Common Polynomials | Description | -|----------|-------------------|-------------------|-------------| -| CRC8 | 0x07 | 0x07, 0x31, 0x9B | 8-bit CRC (1 byte output) | -| CRC16 | 0x8005 | 0x8005, 0x1021, 0x8408 | 16-bit CRC (2 byte output) | -| CRC32 | 0x04C11DB7 | 0x04C11DB7, 0xEDB88320 | 32-bit CRC (4 byte output) | - -### Example Configurations - -**Standard CRC8:** -\`\`\`javascript -crc1.$name = "CRC8_Check"; -crc1.opCode = "m_calculate_crc8"; -crc1.crcPolynomial = 0x07; -crc1.output1Size = "1"; -\`\`\` - -**CRC16 for MODBUS:** -\`\`\`javascript -crc1.$name = "CRC16_MODBUS"; -crc1.opCode = "m_calculate_crc16"; -crc1.crcPolynomial = 0x8005; -crc1.output1Size = "2"; -\`\`\` - -**CRC32 for Ethernet:** -\`\`\`javascript -crc1.$name = "CRC32_Ethernet"; -crc1.opCode = "m_calculate_crc32"; -crc1.crcPolynomial = 0x04C11DB7; -crc1.output1Size = "4"; -\`\`\` - -### Connecting to Other Blocks - -\`\`\`javascript -// Connect data input -scripting.connect(data_source, "output1", crc1, "input1"); - -// Connect CRC output to downstream block -scripting.connect(crc1, "output1", next_block, "input1"); - -// Connect control flow -scripting.connect(prev_block, "next", crc1, "prev"); -scripting.connect(crc1, "next", next_block, "prev"); -\`\`\` - -### Important Notes - -1. **Input Required**: input1 must be connected to provide data for CRC calculation. - -2. **Polynomial Selection**: Choose appropriate polynomial for your protocol/standard. - -3. **Output Size**: Must match CRC type (CRC8=1 byte, CRC16=2 bytes, CRC32=4 bytes). - -4. **Lookup Table**: Block generates optimized lookup table for fast CRC calculation. -`; - -} function getLongDescription(){ - return ` + return `NOTE: Before making any assumptions about this block's parameters, behavior, or configuration, always read the docs file at: docs_ai/application_specific/crc_block.md + ## CRC Block (Cyclic Redundancy Check) ### Purpose @@ -366,7 +287,6 @@ exports = { displayName: "CRC", defaultInstanceName: "CRC_", longDescription: getLongDescription(), - getAIContext: getAIContext, uiView: "graph", templates: { //need to check what can be passed as argument to template file, right now no argument is required diff --git a/.metadata/sysconfig/.meta/pru_blocks/common/pru_blocks_static_module.syscfg.js b/.metadata/sysconfig/.meta/pru_blocks/common/pru_blocks_static_module.syscfg.js index 21a84f5..a5e08e3 100644 --- a/.metadata/sysconfig/.meta/pru_blocks/common/pru_blocks_static_module.syscfg.js +++ b/.metadata/sysconfig/.meta/pru_blocks/common/pru_blocks_static_module.syscfg.js @@ -3,6 +3,10 @@ const pruDMEM0 = system.getScript("/pru_blocks/common/simulation/pru_dmem0.js"); const pruSMEM = system.getScript("/pru_blocks/common/simulation/pru_smem.js"); const pruSimulator = system.getScript("/pru_blocks/common/simulation/pru_core.js"); const simulationData = {cycleCount : [], r30Bits : [], r31Bits : []}; +function createWarnedLabelsGlobal() { + return new Set(); +} +let warnedLabelsGlobal = createWarnedLabelsGlobal(); // ============================================================================ // R31 Simulation Input Functions @@ -917,6 +921,183 @@ function detectControlFlowCycle() { return null; } +/** + * Checks that every disconnected subgraph (chunks with no incoming prev link) + * terminates at a Flow Control block, preventing fallthrough between chunks. + */ +function checkDisconnectedChunks(inst, report) { + const modules = system.modules; + const flowModuleName = "/pru_blocks/program_control/flow_control_block"; + + // Build instance name -> instance map for all PRU blocks + const instanceMap = {}; + for (const modName in modules) { + if (!modName.startsWith("/pru_blocks/")) continue; + const mod = modules[modName]; + if (!mod || !mod.$instances) continue; + for (const instObj of mod.$instances) { + if (instObj && instObj.$name) { + instanceMap[instObj.$name] = instObj; + } + } + } + + // Find all disconnected heads (no incoming prev connection) + const hasIncomingPrev = {}; + for (const name in instanceMap) { + hasIncomingPrev[name] = false; + } + for (const name in instanceMap) { + const instObj = instanceMap[name]; + const prevConnections = (instObj.prev && instObj.prev.length > 0) ? instObj.prev : []; + // If this block has any prev connections, it has incoming control flow + if (prevConnections.length > 0) { + hasIncomingPrev[name] = true; + } + // Also, the source blocks of prev connections feed INTO this block, + // but the block WITH prev is the one that continues the chain. + for (const conn of prevConnections) { + if (conn && conn.inst && conn.inst.$name) { + // The source of prev connection provides flow to this block, + // but does NOT mean the source itself has incoming prev. + // No action needed on source here. + } + } + } + + // Build a set of all block names that live inside any group container + const groupMemberNames = new Set(); + for (const modName in modules) { + if (!modName.startsWith("/pru_blocks/")) continue; + const mod = modules[modName]; + if (!mod || !mod.$instances) continue; + for (const instObj of mod.$instances) { + if (instObj && instObj.$groupContents && Array.isArray(instObj.$groupContents)) { + for (const child of instObj.$groupContents) { + if (child && child.$name) { + groupMemberNames.add(child.$name); + } + } + } + } + } + + // Find heads: blocks with no incoming prev, excluding group containers and infinite loops + const heads = []; + for (const name in instanceMap) { + const instObj = instanceMap[name]; + const prevConnections = (instObj.prev && instObj.prev.length > 0) ? instObj.prev : []; + if (prevConnections.length === 0 && !hasIncomingPrev[name]) { + const modulePath = JSON.parse(JSON.stringify(instObj)).$module || ''; + // Skip memory variable, lookup table, group containers, conditional blocks, + // load constants (pure data sources), and infinite loops + if (modulePath.includes('memory_variable_block') || + modulePath.includes('look_up_table') || + modulePath.includes('access_look_up_table') || + modulePath.includes('group_block') || + modulePath.includes('conditional_block') || + modulePath.includes('load_constant_block') || + (instObj.$groupContents && ('infiniteLoop' in instObj && instObj.infiniteLoop === true))) { + continue; + } + // Skip any block inside a group container (group members have their own flow) + if (groupMemberNames.has(name)) { + continue; + } + // Check if this block's output1 feeds into another block's input + // (i.e., it's a data source for a connected chunk, not a standalone chunk head) + let feedsIntoChain = false; + for (const conn of (instObj.output1 || [])) { + if (conn && conn.inst && conn.inst.$name) { + const targetName = conn.inst.$name; + const targetObj = instanceMap[targetName]; + if (targetObj && (targetObj.prev && targetObj.prev.length > 0 || hasIncomingPrev[targetName])) { + // Skip only if target receives this as DATA INPUT (not as prev control flow) + // A block feeding data into arithmetic should NOT be excluded, + // since arithmetic's chain must still terminate. + const targetPrevConnections = (targetObj.prev && targetObj.prev.length > 0) ? targetObj.prev : []; + const receivesAsPrev = targetPrevConnections.some(p => p && p.inst && p.inst.$name === name); + if (!receivesAsPrev) { + feedsIntoChain = true; + break; + } + } + } + } + if (!feedsIntoChain) { + heads.push(name); + } + } + } + + const visitedAll = new Set(); + const flowModule = modules[flowModuleName]; + + function chunkTerminates(startName) { + const visited = new Set(); + const stack = [startName]; + let reachesFlow = false; + + while (stack.length > 0) { + const currentName = stack.pop(); + if (!currentName || visited.has(currentName)) continue; + visited.add(currentName); + visitedAll.add(currentName); + + const current = instanceMap[currentName]; + if (!current) continue; + + const currentModulePath = JSON.parse(JSON.stringify(current)).$module; + // Flow Control block terminates this chunk (control flow reached) + if (currentModulePath === flowModuleName) { + reachesFlow = true; + return true; + } + + // Also consider data-flow termination: if any output1 consumer is Flow Control, + // this chunk effectively terminates (data reaches termination point) + const outputConsumers = current.output1 ? current.output1.map(c => c?.inst).filter(Boolean) : []; + for (const consumer of outputConsumers) { + if (consumer && consumer.$name) { + const consumerModulePath = JSON.parse(JSON.stringify(instanceMap[consumer.$name])).$module || ''; + if (consumerModulePath === flowModuleName) { + reachesFlow = true; + return true; + } + // Also follow data-flow chain further + stack.push(consumer.$name); + } + } + + // Follow control-flow next port + const nextConnections = (current.next && current.next.length > 0) ? current.next : []; + for (const conn of nextConnections) { + if (conn && conn.inst && conn.inst.$name) { + stack.push(conn.inst.$name); + } + } + } + return reachesFlow; + } + + const failingChunks = []; + for (const head of heads) { + if (!chunkTerminates(head)) { + failingChunks.push(head); + } + } + if (failingChunks.length > 0) { + // Report once per failing chunk, using only the head block instance + // so the error appears on the graph at one point, not for every member. + for (const head of failingChunks) { + report.logError( + `Disconnected chunk '${head}' missing Flow Control termination. Add Flow Control at end of this subgraph.`, + instanceMap[head], "" + ); + } + } +} + function validate(inst, report) { // Check for cycles in the control flow graph before anything else @@ -941,6 +1122,12 @@ function validate(inst, report) ); } + // Check disconnected chunks: each disconnected subgraph must terminate in Flow Control + checkDisconnectedChunks(inst, report); + + // Reset unreachable-chunk tracking for fresh validation (e.g. after changing flow targets) + warnedLabelsGlobal = createWarnedLabelsGlobal(); + //allocating pru registers for all blocks at system level pruRegisterAllocator.allocatePruRegisters(); //validating register allocation @@ -1028,18 +1215,50 @@ function validate(inst, report) // Then replace SMEM symbols pruInstructions = pruSMEM.replaceSymbolReferences(pruInstructions); const r31HistoryMap = collectR31History(); - let {pruState, r30ValueHistory, r31ValueHistory} = pruSimulator.simulatePruInstructions(pruInstructions, pruInstructionsLabels, inst["pruCyclesToSimulate"], r31HistoryMap); + // Post-simulation unreachable-chunk warning (not error) + const simResult = pruSimulator.simulatePruInstructions(pruInstructions, pruInstructionsLabels, inst["pruCyclesToSimulate"], r31HistoryMap); + const visitedLabels = simResult.visitedLabels || new Set(); + const emittedLabels = new Set(); + for (let i = 0; i < pruInstructionsLabels.length; i++) { + const lbl = pruInstructionsLabels[i]; + if (lbl !== 0 && typeof lbl === 'string' && lbl.length > 0) { + emittedLabels.add(lbl); + } + } + // Unreachable-chunk warnings: only for block start labels, once globally + for (const lbl of emittedLabels) { + if (!visitedLabels.has(lbl)) { + const isBlockStart = lbl.endsWith('_start') || lbl.startsWith('startloop_') || lbl.startsWith('endloop_'); + if (isBlockStart && !warnedLabelsGlobal.has(lbl)) { + warnedLabelsGlobal.add(lbl); + // Look up block instance by stripping label suffix + const blockName = lbl.replace(/_start$/, '').replace(/^startloop_/, '').replace(/^endloop_/, ''); + // Build instance map from system modules for lookup + const lookupMap = {}; + for (const modName in system.modules) { + if (!modName.startsWith("/pru_blocks/")) continue; + const mod = system.modules[modName]; + if (!mod || !mod.$instances) continue; + for (const obj of mod.$instances) { + if (obj && obj.$name) lookupMap[obj.$name] = obj; + } + } + const blockInst = lookupMap[blockName] || inst; + report.logWarning( + `Unreachable chunk: label '${lbl}' was emitted but never executed during simulation.`, + blockInst, "" + ); + } + } + } - prepareR30DataForPlotting(r30ValueHistory); - prepareR31DataForPlotting(r31ValueHistory); - // return pruState, r30ValueHistory, and r31ValueHistory - return {pruState, r30ValueHistory, r31ValueHistory} + prepareR30DataForPlotting(simResult.r30ValueHistory); + prepareR31DataForPlotting(simResult.r31ValueHistory); + return {pruState: simResult.pruState, r30ValueHistory: simResult.r30ValueHistory, r31ValueHistory: simResult.r31ValueHistory}; } } -function getAIContext() { - return getLongDescription(); -} + function getLongDescription() { return ` @@ -1158,7 +1377,6 @@ exports = { //this module is not visible to user but error is thrown when it is out of registers displayName: "Simulation Settings", longDescription: getLongDescription(), - getAIContext: getAIContext, moduleStatic: { validate, config: [ diff --git a/.metadata/sysconfig/.meta/pru_blocks/common/pru_syscfg.asm.xdt b/.metadata/sysconfig/.meta/pru_blocks/common/pru_syscfg.asm.xdt index 1f395e1..eb5ebd6 100644 --- a/.metadata/sysconfig/.meta/pru_blocks/common/pru_syscfg.asm.xdt +++ b/.metadata/sysconfig/.meta/pru_blocks/common/pru_syscfg.asm.xdt @@ -108,6 +108,10 @@ sysconfig_generated_start: %if(typeof(labels[iterator]) == "string" && labels[iterator] !== "") %{ `labels[iterator]`: +%if(labels[iterator].endsWith("_end")) +%{ + +%} %} % if((!pruInstructions[iterator].includes("-1")) && (pruInstructions[iterator] != "0") && (!pruInstructions[iterator].includes("undefined"))) % { @@ -128,6 +132,10 @@ sysconfig_generated_start: %if(typeof(labels[iterator]) == "string" && labels[iterator] !== "") %{ `labels[iterator]`: +%if(labels[iterator].endsWith("_end")) +%{ + +%} %} % if((!pruInstructions[iterator].includes("-1")) && (pruInstructions[iterator] != "0") && (!pruInstructions[iterator].includes("undefined"))) % { diff --git a/.metadata/sysconfig/.meta/pru_blocks/common/register_allocation/pru_register_allocator.js b/.metadata/sysconfig/.meta/pru_blocks/common/register_allocation/pru_register_allocator.js index d224604..37bcaae 100644 --- a/.metadata/sysconfig/.meta/pru_blocks/common/register_allocation/pru_register_allocator.js +++ b/.metadata/sysconfig/.meta/pru_blocks/common/register_allocation/pru_register_allocator.js @@ -484,6 +484,7 @@ function pushInstruction(instance, parentInstance) { if (moduleInstanceRegisterMap[instanceName]?.conditionCalculated === 1) { return moduleInstanceRegisterMap[instanceName].label; } + // Process prev port if it exists and is connected let label; if (instance?.["prev"] && instance?.["prev"][0]?.["inst"]) { @@ -619,6 +620,11 @@ function pushInstruction(instance, parentInstance) { }; instruction = `LDI ${getPruRegister(byteOffset, instance.loopCountRegSize)}, ${instance.loopCount}`; addToPruRegisterAllocationSummary(label, instruction, instance, instanceName, 0); + //push _start label between LDI and LOOP. + //NOTE: for finite loops, jumping here re-arms LOOP (counter reloads), + //not a true "continue". Only for infinite loops does jumping to + //_start (startloop_N with QBA) act like a clean continue. + addToPruRegisterAllocationSummary(`${instanceName}_start`, "0", instance, instanceName, 0); //push loop instruction instruction = `LOOP endloop_${moduleInstanceRegisterMap[instanceName].instanceNum}, ${getPruRegister(byteOffset, instance.loopCountRegSize)}`; label = 0; @@ -770,8 +776,27 @@ function pushInstruction(instance, parentInstance) { { moduleInstanceRegisterMap[instanceName]["peakCycles"] += cycleBudgetMap[instanceName]; } + // Emit a universal _start label immediately before this + // block's own instruction, as its addressable entry point for Flow + // Control jumps. Placed here (not at function entry) so it lands right + // above this instruction rather than above the whole prev-chain that + // was just recursively processed. Loop and group blocks are excluded — + // they emit their own specific start labels elsewhere (loop: between + // LDI and LOOP / startloop_N; group: _start). + if (!instance.$groupContents) { + addToPruRegisterAllocationSummary(`${instanceName}_start`, "0", instance, instanceName, 0); + } addToPruRegisterAllocationSummary(label, instruction, instance, instanceName, moduleInstanceRegisterMap[instanceName]["peakCycles"]); - + + // Emit a universal _end label immediately after this + // block's own instruction, as an addressable "done with this block" + // target for Flow Control jumps (e.g. bailing out of a loop from + // inside a nested branch). Excluded for conditional (If/Else) blocks — + // a conditional has two forward addresses (_TRUE/_FALSE), not one, so + // a single _end here would be meaningless. + if (!instance.$groupContents && !(instance.T && instance.F)) { + addToPruRegisterAllocationSummary(`${instanceName}_end`, "0", instance, instanceName, 0); + } return maxBytesUsed; } diff --git a/.metadata/sysconfig/.meta/pru_blocks/common/simulation/pru_core.js b/.metadata/sysconfig/.meta/pru_blocks/common/simulation/pru_core.js index e9609a0..47e2b95 100644 --- a/.metadata/sysconfig/.meta/pru_blocks/common/simulation/pru_core.js +++ b/.metadata/sysconfig/.meta/pru_blocks/common/simulation/pru_core.js @@ -1110,8 +1110,11 @@ function executeInstruction(pruState, pruInstructions, labelMap, r30ValueHistory case 'JMP': { // JMP label const label = operands[0]; - - if (labelMap[label] !== undefined) { + + if (label === 'sysconfig_generated_end') { + // Exit point: stop visiting further labels + pruState.pc = pruInstructions.length; // Force loop exit + } else if (labelMap[label] !== undefined) { pruState.pc = labelMap[label]; } else { // If label not found, increment error counter and move to next instruction @@ -1655,12 +1658,20 @@ function simulatePruInstructions(pruInstructions, pruInstructionsLabels, cycleCo } } + // Track which emitted labels are reached during simulation + // (used for unreachable-chunk detection post-sim) + const visitedLabels = new Set(); + // Execute instructions until cycle count is reached or PC is out of bounds while (pruState.cycles < cycleCount && pruState.pc < pruInstructions.length) { + const currentLabel = pruInstructionsLabels[pruState.pc]; + if (currentLabel !== 0 && typeof currentLabel === 'string') { + visitedLabels.add(currentLabel); + } executeInstruction(pruState, pruInstructions, labelMap, r30ValueHistory, r31ValueHistory, cycleCount); } - return {pruState, r30ValueHistory, r31ValueHistory}; + return {pruState, r30ValueHistory, r31ValueHistory, visitedLabels}; } // Export the functions and constants diff --git a/.metadata/sysconfig/.meta/pru_blocks/data_handling/arithmetic_block.syscfg.js b/.metadata/sysconfig/.meta/pru_blocks/data_handling/arithmetic_block.syscfg.js index bbcbf94..18e76ef 100644 --- a/.metadata/sysconfig/.meta/pru_blocks/data_handling/arithmetic_block.syscfg.js +++ b/.metadata/sysconfig/.meta/pru_blocks/data_handling/arithmetic_block.syscfg.js @@ -8,98 +8,11 @@ function validate(inst, report) { } } -function getAIContext(){ - return getLongDescription() + ` -## How to Configure (For AI/Scripting) - -This section describes how to programmatically configure the Arithmetic block in a .syscfg file. - -### Adding an Arithmetic Instance - -\\\`\\\`\\\`javascript -const arithmetic_block = scripting.addModule("/pru_blocks/data_handling/arithmetic_block", {}, false); -const arith1 = arithmetic_block.addInstance(); -\\\`\\\`\\\` - -### Configuration Parameters - -| Parameter | Type | Valid Values | Default | Description | -|-----------|------|--------------|---------|-------------| -| opCode | String | "ADD", "ADC", "SUB", "SUC" | "ADC" | Math operation to perform | -| output1Size | String | "maxOfInputs", "1", "2", "4" | "maxOfInputs" | Output size in bytes | - -### Valid Values for opCode - -| Value | Display Name | Description | -|-------|--------------|-------------| -| "ADD" | Addition | result = input1 + input2 | -| "ADC" | Addition With Carry | result = input1 + input2 + carry | -| "SUB" | Subtract | result = input1 - input2 | -| "SUC" | Subtract With Borrow | result = input1 - input2 - borrow | - -### Valid Values for output1Size - -| Value | Display Name | Description | -|-------|--------------|-------------| -| "maxOfInputs" | Maximum of Inputs | Auto-size based on largest input | -| "1" | One byte | Force 8-bit result | -| "2" | two bytes | Force 16-bit result | -| "4" | four bytes | Force 32-bit result | - -### Example Configurations - -**Simple Addition:** -\\\`\\\`\\\`javascript -arith1.$name = "Add_Values"; -arith1.opCode = "ADD"; -arith1.output1Size = "maxOfInputs"; -\\\`\\\`\\\` - -**Subtraction with 32-bit output:** -\\\`\\\`\\\`javascript -arith1.$name = "Subtract_32bit"; -arith1.opCode = "SUB"; -arith1.output1Size = "4"; -\\\`\\\`\\\` - -**Addition with carry (for multi-precision):** -\\\`\\\`\\\`javascript -arith1.$name = "Add_With_Carry"; -arith1.opCode = "ADC"; -arith1.output1Size = "4"; -\\\`\\\`\\\` - -### Connecting to Other Blocks - -\\\`\\\`\\\`javascript -// Connect two data sources to inputs -scripting.connect(load_constant1, "output1", arith1, "input1"); -scripting.connect(load_constant2, "output1", arith1, "input2"); - -// Connect output to downstream block -scripting.connect(arith1, "output1", next_block, "input1"); - -// Connect control flow -scripting.connect(prev_block, "next", arith1, "prev"); -scripting.connect(arith1, "next", next_block, "prev"); -\\\`\\\`\\\` - -### Important Notes - -1. **Two Inputs Required**: Both input1 and input2 must be connected. - -2. **Carry/Borrow Flag**: ADC and SUC use the carry/borrow flag from previous arithmetic operations. - -3. **Single Cycle**: All arithmetic operations complete in 1 PRU cycle. - -4. **Overflow**: Results wrap around - no overflow detection. -`; - -} function getLongDescription() { - return ` + return `NOTE: Before making any assumptions about this block's parameters, behavior, or configuration, always read the docs file at: docs_ai/data_handling/arithmetic_block.md + ## Arithmetic Block ### Purpose @@ -269,5 +182,4 @@ exports = { }] }, }, - getAIContext } \ No newline at end of file diff --git a/.metadata/sysconfig/.meta/pru_blocks/data_handling/bitwise_block.syscfg.js b/.metadata/sysconfig/.meta/pru_blocks/data_handling/bitwise_block.syscfg.js index dede553..3d3ab65 100644 --- a/.metadata/sysconfig/.meta/pru_blocks/data_handling/bitwise_block.syscfg.js +++ b/.metadata/sysconfig/.meta/pru_blocks/data_handling/bitwise_block.syscfg.js @@ -8,116 +8,11 @@ function validate(inst, report) { } } -function getAIContext(){ - return getLongDescription() + ` -## How to Configure (For AI/Scripting) - -This section describes how to programmatically configure the Bitwise block in a .syscfg file. - -### Adding a Bitwise Instance - -\\\`\\\`\\\`javascript -const bitwise_block = scripting.addModule("/pru_blocks/data_handling/bitwise_block", {}, false); -const bitwise1 = bitwise_block.addInstance(); -\\\`\\\`\\\` - -### Configuration Parameters - -| Parameter | Type | Valid Values | Default | Description | -|-----------|------|--------------|---------|-------------| -| opCode | String | "AND", "OR", "XOR", "NOT", "LSL", "LSR" | "AND" | Bitwise operation to perform | -| output1Size | String | "maxOfInputs", "1", "2", "4" | "maxOfInputs" | Output size in bytes | - -### Valid Values for opCode - -| Value | Inputs | Description | -|-------|--------|-------------| -| "AND" | 2 | Bitwise AND: result = input1 & input2 | -| "OR" | 2 | Bitwise OR: result = input1 \| input2 | -| "XOR" | 2 | Bitwise XOR: result = input1 ^ input2 | -| "NOT" | 1 | Bitwise NOT: result = ~input1 | -| "LSL" | 2 | Logical Shift Left: result = input1 << input2 | -| "LSR" | 2 | Logical Shift Right: result = input1 >> input2 | - -### Valid Values for output1Size - -| Value | Display Name | Description | -|-------|--------------|-------------| -| "maxOfInputs" | Maximum of Inputs | Auto-size based on largest input | -| "1" | One byte | Force 8-bit result | -| "2" | two bytes | Force 16-bit result | -| "4" | four bytes | Force 32-bit result | - -### Example Configurations - -**Bitwise AND (masking):** -\\\`\\\`\\\`javascript -bitwise1.$name = "Mask_Bits"; -bitwise1.opCode = "AND"; -bitwise1.output1Size = "maxOfInputs"; -\\\`\\\`\\\` - -**Bitwise OR (setting flags):** -\\\`\\\`\\\`javascript -bitwise1.$name = "Set_Flags"; -bitwise1.opCode = "OR"; -bitwise1.output1Size = "4"; -\\\`\\\`\\\` - -**Bitwise NOT (invert):** -\\\`\\\`\\\`javascript -bitwise1.$name = "Invert_Bits"; -bitwise1.opCode = "NOT"; -bitwise1.output1Size = "maxOfInputs"; -\\\`\\\`\\\` - -**Left Shift:** -\\\`\\\`\\\`javascript -bitwise1.$name = "Shift_Left"; -bitwise1.opCode = "LSL"; -bitwise1.output1Size = "4"; -\\\`\\\`\\\` - -**Right Shift:** -\\\`\\\`\\\`javascript -bitwise1.$name = "Shift_Right"; -bitwise1.opCode = "LSR"; -bitwise1.output1Size = "maxOfInputs"; -\\\`\\\`\\\` - -### Connecting to Other Blocks - -\\\`\\\`\\\`javascript -// For two-input operations (AND, OR, XOR, LSL, LSR) -scripting.connect(data_source, "output1", bitwise1, "input1"); -scripting.connect(mask_or_shift_amount, "output1", bitwise1, "input2"); - -// For single-input operation (NOT) -scripting.connect(data_source, "output1", bitwise1, "input1"); - -// Connect output to downstream block -scripting.connect(bitwise1, "output1", next_block, "input1"); - -// Connect control flow -scripting.connect(prev_block, "next", bitwise1, "prev"); -scripting.connect(bitwise1, "next", next_block, "prev"); -\\\`\\\`\\\` - -### Important Notes - -1. **Input Count**: NOT requires 1 input; all other operations require 2 inputs. - -2. **Single Cycle**: All bitwise operations complete in 1 PRU cycle. - -3. **Shift Amount**: For LSL/LSR, input2 specifies the number of bit positions to shift. - -4. **Logical Shift**: LSL and LSR fill vacated bits with zeros (no sign extension). -`; -} function getLongDescription() { - return ` + return `NOTE: Before making any assumptions about this block's parameters, behavior, or configuration, always read the docs file at: docs_ai/data_handling/bitwise_block.md + ## Bitwise Block ### Purpose @@ -326,5 +221,4 @@ exports = { }] }, }, - getAIContext } \ No newline at end of file diff --git a/.metadata/sysconfig/.meta/pru_blocks/data_handling/load_constant_block.syscfg.js b/.metadata/sysconfig/.meta/pru_blocks/data_handling/load_constant_block.syscfg.js index bae4c7c..bcdb0e7 100644 --- a/.metadata/sysconfig/.meta/pru_blocks/data_handling/load_constant_block.syscfg.js +++ b/.metadata/sysconfig/.meta/pru_blocks/data_handling/load_constant_block.syscfg.js @@ -25,86 +25,11 @@ function getNumOfBytes(value) return 4; } -function getAIContext() { - return getLongDescription() + ` -## How to Configure (For AI/Scripting) - -This section describes how to programmatically configure the Load Constant block in a .syscfg file. - -### Adding a Load Constant Instance - -\\\`\\\`\\\`javascript -const load_constant_block = scripting.addModule("/pru_blocks/data_handling/load_constant_block", {}, false); -const ldi1 = load_constant_block.addInstance(); -\\\`\\\`\\\` - -### Configuration Parameters - -| Parameter | Type | Valid Values | Default | Description | -|-----------|------|--------------|---------|-------------| -| constant1 | Integer | 0 to 0xFFFFFFFF | 0 | Constant value to load | - -### Example Configurations - -**Load small value (8-bit, uses LDI):** -\\\`\\\`\\\`javascript -ldi1.$name = "Load_Small"; -ldi1.constant1 = 0x55; // 85 decimal -\\\`\\\`\\\` - -**Load medium value (16-bit, uses LDI):** -\\\`\\\`\\\`javascript -ldi1.$name = "Load_Medium"; -ldi1.constant1 = 0x1234; // 4660 decimal -\\\`\\\`\\\` - -**Load large value (32-bit, uses LDI32):** -\\\`\\\`\\\`javascript -ldi1.$name = "Load_Large"; -ldi1.constant1 = 0xDEADBEEF; // 3735928559 decimal -\\\`\\\`\\\` - -**Load bit mask:** -\\\`\\\`\\\`javascript -ldi1.$name = "Bit_Mask"; -ldi1.constant1 = 0xFF00FF00; // Alternating byte mask -\\\`\\\`\\\` - -**Load zero:** -\\\`\\\`\\\`javascript -ldi1.$name = "Zero_Value"; -ldi1.constant1 = 0; -\\\`\\\`\\\` - -### Connecting to Other Blocks - -\\\`\\\`\\\`javascript -// Connect output to downstream block (e.g., arithmetic, UART TX, SPI) -scripting.connect(ldi1, "output1", arithmetic_block, "input1"); - -// Connect control flow -scripting.connect(prev_block, "next", ldi1, "prev"); -scripting.connect(ldi1, "next", next_block, "prev"); -\\\`\\\`\\\` - -### Important Notes - -1. **Source Block**: Load Constant has no input - it's a data source. - -2. **Auto-sizing**: The block automatically selects LDI (1 cycle) for values ≤ 0xFFFF and LDI32 (2 cycles) for larger values. - -3. **Output Size**: Output register size is automatically determined: -- 1 byte for values 0-255 -- 2 bytes for values 256-65535 -- 4 bytes for values > 65535 - -4. **Hexadecimal**: Values can be specified in hex (0x prefix) or decimal. -`; -} function getLongDescription() { - return ` + return `NOTE: Before making any assumptions about this block's parameters, behavior, or configuration, always read the docs file at: docs_ai/data_handling/load_constant_block.md + ## Load Constant Block ### Purpose @@ -156,7 +81,6 @@ exports = { displayName: "Load Constant", defaultInstanceName: "Load_Constant_", longDescription: getLongDescription(), - getAIContext: getAIContext, uiView: "graph", templates: { //need to check what can be passed as argument to template file, right now no argument is required diff --git a/.metadata/sysconfig/.meta/pru_blocks/program_control/conditional_block.syscfg.js b/.metadata/sysconfig/.meta/pru_blocks/program_control/conditional_block.syscfg.js index e93f8ae..e5a59fe 100644 --- a/.metadata/sysconfig/.meta/pru_blocks/program_control/conditional_block.syscfg.js +++ b/.metadata/sysconfig/.meta/pru_blocks/program_control/conditional_block.syscfg.js @@ -1,11 +1,84 @@ +const FLOW_CONTROL_MODULE = "/pru_blocks/program_control/flow_control_block"; +const CONDITIONAL_MODULE = "/pru_blocks/program_control/conditional_block"; + +/** + * Walks forward from a T/F branch head via BOTH "next" (control flow) and + * "output1" (data flow fanout) connections — matching the reachability + * model already used elsewhere for branch chains (collectBranchChain in + * pru_register_allocator.js) and cycle detection (detectControlFlowCycle + * in pru_blocks_static_module.syscfg.js). A branch head with no outgoing + * "next" of its own can still be "handled" if a data consumer of its + * output eventually reaches a Flow Control block via ITS OWN "next" chain + * (e.g. Memory_Access -> Arithmetic.input1 (data) -> Arithmetic.next -> + * Flow Control). Only a genuine dead end (no next, no output1 consumers, + * and not a Flow Control block itself) on every reachable path is an error. + * If the chain reaches a nested conditional block, both of ITS T and F + * branches must recursively terminate the same way. + * Returns an error message, or null if the branch terminates correctly. + */ +function branchTerminates(headInst, ownerName, branchLabel) { + const visited = new Set(); + + function walk(current) { + if (!current || !current.$name || visited.has(current.$name)) { + return true; // Already visited (or a cycle, reported separately) — treat as handled + } + visited.add(current.$name); + + // $module is a live object reference on the instance; round-trip + // through JSON to get the plain module path string for comparison + // (matches the pattern used elsewhere in this codebase, e.g. + // crc_block.syscfg.js). + const currentModulePath = JSON.parse(JSON.stringify(current)).$module; + + if (currentModulePath === FLOW_CONTROL_MODULE) { + return true; // This path terminates correctly + } + + if (currentModulePath === CONDITIONAL_MODULE) { + const trueHead = current.T?.[0]?.inst; + const falseHead = current.F?.[0]?.inst; + if (!trueHead || !falseHead) { + // Nested conditional with an unconnected branch is caught by + // its own validate() call; don't double-report here. + return true; + } + // Both of the nested conditional's own branches must terminate. + return walk(trueHead) && walk(falseHead); + } + + const nextInst = current.next?.[0]?.inst; + const outputConsumers = current.output1 ? current.output1.map(c => c?.inst).filter(Boolean) : []; + + if (!nextInst && outputConsumers.length === 0) { + return false; // Genuine dead end, never reached a Flow Control block + } + + let handled = false; + if (nextInst) { + handled = walk(nextInst) || handled; + } + for (const consumer of outputConsumers) { + handled = walk(consumer) || handled; + } + return handled; + } + + const terminatesOk = walk(headInst); + if (terminatesOk) { + return null; + } + return `${ownerName}'s ${branchLabel} branch does not reach a Flow Control block on any path. Without one, execution falls through into the other branch. Add a Flow Control block at the end of this branch (directly, or via a data-consuming block's own control-flow chain).`; +} + function validate(inst, report) { for(let iterator = 1; iterator <= inst["numOfInputPorts"]; iterator++) { if(inst["input"+iterator.toString()].length == 0) { - report.logWarning("input"+iterator.toString()+" port not connected to output port",inst) + report.logWarning("input"+iterator.toString()+" port not connected to output port",inst) } - } + } //verifying if true port is connected true/false port(conditional input) are not if((inst["T"].length == 0)) { @@ -16,95 +89,28 @@ function validate(inst, report) { { report.logWarning("f_next port is not connected",inst); } -} - -function getAIContext() { - return getLongDescription() + ` - -## How to Configure (For AI/Scripting) - -This section describes how to programmatically configure the If/Else (Conditional) block in a .syscfg file. - -### Adding an If/Else Instance - -\\\`\\\`\\\`javascript -const conditional_block = scripting.addModule("/pru_blocks/program_control/conditional_block", {}, false); -const if_else1 = conditional_block.addInstance(); -\\\`\\\`\\\` - -### Configuration Parameters -| Parameter | Type | Valid Values | Default | Description | -|-----------|------|--------------|---------|-------------| -| conditionToCheck | String | See table below | "greaterThanInput2" | Comparison operation | - -### Valid Values for conditionToCheck - -| Value | Display Name | PRU Instruction | Description | -|-------|--------------|-----------------|-------------| -| "greaterThanInput2" | Greater Than Input2 | QBGT | input1 > input2 | -| "lessThanInput2" | Less Than Input2 | QBLT | input1 < input2 | -| "equalToInput2" | Equal To Input2 | QBEQ | input1 == input2 | -| "notEqualToInput2" | Not Equal To Input2 | QBNE | input1 != input2 | -| "greaterThanEqualtoInput2" | Greater Than Or Equal To Input2 | QBGE | input1 >= input2 | -| "lessThanEqualtoInput2" | Less Than Or Equal To Input2 | QBLE | input1 <= input2 | - -### Example Configurations - -**Check if value is greater than threshold:** -\\\`\\\`\\\`javascript -if_else1.$name = "Check_Threshold"; -if_else1.conditionToCheck = "greaterThanInput2"; -\\\`\\\`\\\` - -**Check for equality:** -\\\`\\\`\\\`javascript -if_else1.$name = "Check_Equal"; -if_else1.conditionToCheck = "equalToInput2"; -\\\`\\\`\\\` - -**Check if not zero:** -\\\`\\\`\\\`javascript -if_else1.$name = "Check_Not_Zero"; -if_else1.conditionToCheck = "notEqualToInput2"; -// Connect input1 to value, input2 to Load_Constant with value 0 -\\\`\\\`\\\` - -### Connecting to Other Blocks - -\\\`\\\`\\\`javascript -// Connect comparison inputs -scripting.connect(value_block, "output1", if_else1, "input1"); -scripting.connect(threshold_block, "output1", if_else1, "input2"); - -// Connect true path (executes when condition is TRUE) -scripting.connect(if_else1, "T", true_path_block, "prev"); - -// Connect false path (executes when condition is FALSE) -scripting.connect(if_else1, "F", false_path_block, "prev"); - -// Connect control flow input -scripting.connect(prev_block, "next", if_else1, "prev"); -\\\`\\\`\\\` - -### Important Notes - -1. **Two Inputs Required**: Both input1 and input2 must be connected for comparison. - -2. **Two Output Paths**: Connect blocks to both T (true) and F (false) ports. - -3. **Unsigned Comparison**: All comparisons treat values as unsigned integers. - -4. **Single Cycle**: Comparison and branch decision execute in 1 PRU cycle. - -5. **Port Names**: True path uses "T" port, False path uses "F" port (displayed as t_next/f_next). - -6. **Terminate Each Branch with a Flow Control Block**: The code generator places the FALSE path immediately after the branch instruction, with the TRUE path at the branch target label. If the FALSE path has no explicit terminator, execution falls through into the TRUE path — causing both branches to execute regardless of the condition. Always end each branch (T and F) with a Flow Control block (HALT or END) to prevent this fall-through. -`; + // Any branch that IS connected must terminate in a Flow Control block, + // otherwise it falls through into the other branch's code. + const trueHead = inst.T?.[0]?.inst; + if (trueHead) { + const err = branchTerminates(trueHead, inst.$name, "T"); + if (err) { + report.logError(err, inst, "T"); + } + } + const falseHead = inst.F?.[0]?.inst; + if (falseHead) { + const err = branchTerminates(falseHead, inst.$name, "F"); + if (err) { + report.logError(err, inst, "F"); + } + } } function getLongDescription() { - return ` + return `NOTE: Before making any assumptions about this block's parameters, behavior, or configuration, always read the docs file at: docs_ai/program_control/conditional_block.md + ## If/Else Block (Conditional Branching) ### Purpose @@ -132,12 +138,14 @@ Implements conditional logic (IF/ELSE statements) to control program flow based **Generated Assembly**: - ; Example: Greater Than Input2 (QBGT) -- QBGT TRUE_LABEL, input1_reg, input2_reg ; Branch if input1 > input2 (1 cycle) +- FalseBranchHead_start: +- QBGT If_Else_0_TRUE, input1_reg, input2_reg ; Branch if input1 > input2 (1 cycle) - ; FALSE path code here -- QBA END_LABEL ; Jump to end -- TRUE_LABEL: +- ; FALSE branch MUST end in a Flow Control block (e.g. JMP sysconfig_generated_end) +- If_Else_0_TRUE: +- TrueBranchHead_start: - ; TRUE path code here -- END_LABEL: +- ; TRUE branch MUST end in a Flow Control block **PRU Branch Instructions**: - **QBGT**: Quick Branch if Greater Than (unsigned comparison) @@ -170,7 +178,11 @@ Implements conditional logic (IF/ELSE statements) to control program flow based - The conditional check happens instantly (1 cycle) - Code on both branches is generated, only one path executes at runtime - This block does not produce an output value - it only controls flow -- **Always terminate each branch (T and F) with a Flow Control block**: The FALSE path falls through to the TRUE path in the generated assembly unless explicitly stopped. Without a terminator on the FALSE branch, both branches execute sequentially regardless of the condition result. +- **Any connected branch (T or F) MUST terminate in a Flow Control block**: The FALSE path falls through to the TRUE path in the generated assembly unless explicitly stopped, and vice versa. SysConfig validation now enforces this as an error — connect a Flow Control block at the end of every connected branch. Leaving a branch entirely unconnected is fine; only connected-but-unterminated branches are rejected. +- **What that Flow Control block should jump to depends on where the If/Else block lives**: + - **Standalone If/Else** (not inside a Loop block): jump to Sysconfig Generated End, Halt, or any other block's \`_start\`/\`_end\` target. + - **If/Else nested inside a Loop block**: jump to that Loop's \`_start\` target so execution resumes the loop instead of exiting the whole program. Jumping to Sysconfig Generated End or Halt from inside a loop's branch ends the entire program early rather than just this iteration — only intentional if that's really the goal. To break out of the loop early (without ending the whole program), jump to the Loop's \`_end\` target instead. +- Every block, including this one and every block on either branch, has an addressable \`_start\` entry point that a Flow Control block elsewhere in the design can jump to (e.g. to re-run this comparison, or to re-enter a Loop block from inside a branch). ### Terminology - **Conditional branching**: Changing program flow based on a condition @@ -189,7 +201,6 @@ exports = { displayName: "If/Else", defaultInstanceName: "If_Else_", longDescription: getLongDescription(), - getAIContext: getAIContext, uiView: "graph", templates: { //need to check what can be passed as argument to template file, right now no argument is required diff --git a/.metadata/sysconfig/.meta/pru_blocks/program_control/flow_control_block.syscfg.js b/.metadata/sysconfig/.meta/pru_blocks/program_control/flow_control_block.syscfg.js index 37fc906..28333b9 100644 --- a/.metadata/sysconfig/.meta/pru_blocks/program_control/flow_control_block.syscfg.js +++ b/.metadata/sysconfig/.meta/pru_blocks/program_control/flow_control_block.syscfg.js @@ -1,3 +1,89 @@ +/** + * Enumerates every real, user-meaningful label in the current design that + * a Flow Control block can validly jump to: every block's _start + * (entry point) and, for ordinary blocks, _end (exit + * point). Loop blocks do NOT expose `_end`. Conditional (If/Else) blocks only expose + * _start, since they have two forward addresses (_TRUE/_FALSE) rather + * than one "end". Excludes internal hardware labels (endloop_N; the + * startloop_N numeric suffix is kept since it's the only re-entry point + * infinite loops have, but conditional branch labels + * If_Else_x_TRUE/FALSE are excluded since those are branch-instruction + * targets, not block entry/exit points). + * @returns {{name: string, displayName: string}[]} + */ +function getValidJumpTargets() { + const targets = []; + // Option A: filter dropdown targets against actually-emitted labels + let emittedLabels = new Set(); + try { + const allocator = system.getScript("/pru_blocks/common/register_allocation/pru_register_allocator.js"); + if (allocator && allocator.getPruRegisterAllocationSummary) { + const summary = allocator.getPruRegisterAllocationSummary(); + if (summary && summary.labels) { + for (const lbl of summary.labels) { + if (typeof lbl === 'string' && lbl.length > 0 && lbl !== '0') { + emittedLabels.add(lbl); + } + } + } + } + } catch (e) {} + + for (const moduleName in system.modules) { + if (!moduleName.startsWith("/pru_blocks/")) continue; + const module = system.modules[moduleName]; + if (!module || !module.$instances) continue; + + for (let i = 0; i < module.$instances.length; i++) { + const inst = module.$instances[i]; + if (!inst || typeof inst !== 'object' || !inst.$name) continue; + + if (inst.$groupContents) { + // Group block: exposed target is _start + if ('infiniteLoop' in inst) { + // Loop block + if (inst.infiniteLoop === true) { + targets.push({ + name: `startloop_${i}`, + displayName: `${inst.$name} (loop start)` + }); + } else { + targets.push({ + name: `${inst.$name}_start`, + displayName: `${inst.$name} (loop start)` + }); + } + // Note: Loop blocks do not expose an _end label. Break via Flow Control to the next block or sysconfig_generated_end. + } else { + // Group block + const groupName = inst.groupName || inst.$name; + targets.push({ + name: `${groupName}_start`, + displayName: `${inst.$name} (group start)` + }); + } + } else if (inst.T && inst.F) { + // Conditional (If/Else) block: only _start is exposed — a + // conditional has two forward addresses (_TRUE/_FALSE), not + // a single "end", so no _end target is offered for it. + targets.push({ + name: `${inst.$name}_start`, + displayName: inst.$name + }); + } else { + // Ordinary block: only _start offered; _end stays emitted in assembly + // but removed from dropdown (redundant with next block start). + targets.push({ + name: `${inst.$name}_start`, + displayName: inst.$name + }); + } + } + } + + return targets.filter(t => emittedLabels.has(t.name)); +} + function validate(inst, report) { for(let iterator = 1; iterator <= inst["numOfInputPorts"]; iterator++) { @@ -6,114 +92,59 @@ function validate(inst, report) { report.logWarning("input"+iterator.toString()+" port not connected to output port",inst) } } -} - -function getAIContext() { - return getLongDescription() + ` - -## How to Configure (For AI/Scripting) - -This section describes how to programmatically configure the Flow Control block in a .syscfg file. - -### Adding a Flow Control Instance - -\\\`\\\`\\\`javascript -const flow_control_block = scripting.addModule("/pru_blocks/program_control/flow_control_block", {}, false); -const flow1 = flow_control_block.addInstance(); -\\\`\\\`\\\` - -### Configuration Parameters - -| Parameter | Type | Valid Values | Default | Description | -|-----------|------|--------------|---------|-------------| -| opCode | String | "JMP", "HALT" | "JMP" | Jump target: end of generated code or halt | - -### Valid Values for opCode - -| Value | Display Name | Description | -|-------|--------------|-------------| -| "JMP" | Sysconfig Generated End | Jump to end label of generated code | -| "HALT" | Halt | Immediately stop PRU execution | - -### Example Configurations - -**Jump to end (normal exit):** -\\\`\\\`\\\`javascript -flow1.$name = "Flow_Control_End"; -flow1.opCode = "JMP"; -\\\`\\\`\\\` - -**Halt PRU immediately:** -\\\`\\\`\\\`javascript -flow1.$name = "Flow_Control_Halt"; -flow1.opCode = "HALT"; -\\\`\\\`\\\` - -### Connecting to Other Blocks - -\\\`\\\`\\\`javascript -// Flow Control is a terminating block - only has prev port, no next -scripting.connect(prev_block, "next", flow1, "prev"); - -// Often used after conditional block's true or false path -scripting.connect(if_else1, "T", flow1, "prev"); // Exit on true condition -\\\`\\\`\\\` -### Important Notes - -1. **Terminating Block**: Flow Control has no output ports - it ends the execution path. - -2. **No Next Port**: Cannot connect anything to this block's output - execution ends here. + const validNames = new Set(["JMP", "HALT", ...getValidJumpTargets().map(t => t.name)]); + if (!validNames.has(inst["jumpTarget"])) { + report.logError(`"${inst["jumpTarget"]}" is not a valid jump target in the current design. Re-select a target — it may have been renamed or removed.`, inst, "jumpTarget"); + } +} -3. **JMP vs HALT**: Use JMP for normal exits (allows cleanup code), HALT for immediate stops. -4. **Single Cycle**: Both JMP and HALT execute in 1 PRU cycle. -`; -} function getLongDescription() { - return ` + return `NOTE: Before making any assumptions about this block's parameters, behavior, or configuration, always read the docs file at: docs_ai/program_control/flow_control_block.md + ## Flow Control Block ### Purpose -Controls PRU program flow by either jumping to the end of generated code or halting the PRU. +Controls PRU program flow by jumping to the end of generated code, halting the PRU, or jumping to the entry point of any other block in the design. ### How It Works 1. **Place in Flow**: Position this block where you want to control program flow -2. **Select Jump Target**: Choose between END or HALT +2. **Select Jump Target**: Pick from a single dropdown — Sysconfig Generated End, Halt, or the entry/exit point of any block in the design 3. **Execution**: When reached, performs the selected jump 4. **No Output**: This is a **terminating block** - no next connections ### Configuration -**Jump To**: Select where the program should jump +**Jump To**: A single dropdown listing every valid jump target in the current design: -**Option 1: Sysconfig Generated End** -- Jumps to the end label of the SysConfig-generated code -- Allows any cleanup code or epilogue to execute -- Recommended for normal program completion -- Generated instruction: JMP sysconfig_generated_end +- **Sysconfig Generated End**: Jumps to the end label of the SysConfig-generated code. Allows any cleanup code or epilogue to execute. Recommended for normal program completion. Generated instruction: \`JMP sysconfig_generated_end\` +- **Halt**: Immediately stops the PRU execution. Puts PRU into halt state, no cleanup or epilogue runs. Generated instruction: \`HALT\`. Use for emergency stops or when no cleanup needed. +- **Any block's "start"**: Every block has an addressable entry point. -**Option 2: Halt** -- Immediately stops the PRU execution -- Puts PRU into halt state -- No cleanup or epilogue runs -- Generated instruction: HALT -- Use for emergency stops or when no cleanup needed +### _start targets + +- Every block exposes \`_start\` — jump here to (re-)run that block from its entry point. ### Technical Details (Additional Information) -**Generated Assembly** (END): +**Generated Assembly** (Sysconfig Generated End): \`\`\`asm JMP sysconfig_generated_end ; Jump to end label (1 cycle) \`\`\` -**Generated Assembly** (HALT): +**Generated Assembly** (Halt): \`\`\`asm HALT ; Halt immediately (1 cycle) \`\`\` -**Performance**: Both options execute in 1 PRU cycle +**Generated Assembly** (block target): +\`\`\`asm +JMP Loop_0_start ; Jump to the selected block's entry/exit point (1 cycle) +\`\`\` + +**Performance**: Every jumpTarget option executes in 1 PRU cycle ### Block Appearance - **Shape**: Circle (distinct from square data processing blocks) @@ -122,15 +153,20 @@ HALT ; Halt immediately (1 cycle) ### Usage Notes - This is a **terminating block** - it has no output connections -- Use END for normal program exits (recommended default) -- Use HALT for emergency stops or when cleanup isn't needed +- Use Sysconfig Generated End for normal program exits (recommended default) +- Use Halt for emergency stops or when cleanup isn't needed +- Select any other block's entry/exit point directly from the same dropdown — no separate free-text field - Multiple FLOW_CONTROL blocks can exist in different program paths +- Every disconnected subgraph (chunk with no incoming "prev") must terminate in Flow Control; validated as warning ("checkDisconnectedChunks"). +- Unreachable emitted labels (e.g. block "_start") that never execute during simulation trigger warnings (unreachable-chunk detection). +- **Every If/Else (Conditional) branch that is connected MUST end in a Flow Control block**: An If/Else block's TRUE and FALSE branches are NOT mutually exclusive in the generated assembly unless each branch is explicitly terminated — without a terminator, execution falls from one branch straight into the other and runs both. SysConfig now enforces this as a validation error, not just a warning — connect a Flow Control block (any jumpTarget) at the end of every connected T/F branch. ### Terminology - **Flow control**: Directing program execution path - **Terminating block**: Block with no output - ends execution path - **HALT**: PRU instruction that stops core execution - **JMP**: Jump instruction that transfers control to a label +- **jumpTarget**: The single dropdown selecting where this block jumps to — Sysconfig Generated End, Halt, or any real \`_start\`/\`_end\` target in the design, validated against the current design, not free text --- `; } @@ -139,7 +175,6 @@ exports = { displayName: "Flow Control", defaultInstanceName: "Flow_Control_", longDescription: getLongDescription(), - getAIContext: getAIContext, uiView: "graph", templates: { //need to check what can be passed as argument to template file, right now no argument is required @@ -157,10 +192,11 @@ exports = { default: "", }, { - name: "opCode", + name: "jumpTarget", displayName: "Jump To", + description: "Where to jump when this block is reached. Includes every real, currently-existing block entry (_start) and exit (_end) point in the design — validated, not free text.", default: "JMP", - options: [ + options: (inst) => [ { name: "JMP", displayName: "SysConfig Generated End", @@ -168,19 +204,31 @@ exports = { { name: "HALT", displayName: "Halt", - } + }, + ...getValidJumpTargets() ], }, + { + name: "opCode", + hidden: true, + default: "JMP", + getValue: (inst) => { + return (inst["jumpTarget"] === "HALT") ? "HALT" : "JMP"; + } + }, { name: "constant1", default: "sysconfig_generated_end", getValue: (inst) => { - if(inst["opCode"] == "JMP"){ + if(inst["jumpTarget"] == "JMP"){ return "sysconfig_generated_end"; } - else{ + else if(inst["jumpTarget"] == "HALT"){ return ""; } + else{ + return inst["jumpTarget"]; + } }, hidden: true }, diff --git a/.metadata/sysconfig/.meta/pru_blocks/program_control/group_block.syscfg.js b/.metadata/sysconfig/.meta/pru_blocks/program_control/group_block.syscfg.js index bb6aa85..585e381 100644 --- a/.metadata/sysconfig/.meta/pru_blocks/program_control/group_block.syscfg.js +++ b/.metadata/sysconfig/.meta/pru_blocks/program_control/group_block.syscfg.js @@ -31,182 +31,11 @@ function validate(inst, report) { } } -function getAIContext() { - return getLongDescription() + ` -## How to Configure (For AI/Scripting) -This section describes how to programmatically configure the Group block in a .syscfg file. - -### Adding a Group Instance - -\\\`\\\`\\\`javascript -const group_block = scripting.addModule("/pru_blocks/program_control/group_block", {}, false); -const group_block1 = group_block.addInstance(); -\\\`\\\`\\\` - -### Configuration Parameters - -| Parameter | Type | Valid Values | Default | Description | -|-----------|------|--------------|---------|-------------| -| groupName | String | Valid identifier (letters, numbers, underscore) | "" | Unique name for the group (becomes assembly label) | -| $size | Array | [width, height] | [500, 250] | Size of the group container in pixels | - -### Naming Rules for groupName - -- Must be a valid C identifier -- Can contain letters (a-z, A-Z), numbers (0-9), and underscore (_) -- Cannot start with a number -- Must be unique across all groups -- Recommended: Keep under 32 characters - -### Example Configurations - -**Create a group with blocks inside:** -\\\`\\\`\\\`javascript -group_block1.$name = "Group_0"; -group_block1.groupName = "my_group"; -group_block1.$size = [500, 320]; -\\\`\\\`\\\` - -### Adding Blocks Inside the Group - -\\\`\\\`\\\`javascript -// Use $groupContents to specify which blocks are inside the group -group_block1.$groupContents = [load_constant_block3, load_constant_block4, conditional_block2, pru_gpo_block1, pru_gpo_block2]; -\\\`\\\`\\\` - -### Complete Example with Conditional Inside Group - -\\\`\\\`\\\`javascript -// Create blocks -const load_constant_block = scripting.addModule("/pru_blocks/data_handling/load_constant_block", {}, false); -const load_constant_block3 = load_constant_block.addInstance(); -const load_constant_block4 = load_constant_block.addInstance(); - -const conditional_block = scripting.addModule("/pru_blocks/program_control/conditional_block", {}, false); -const conditional_block2 = conditional_block.addInstance(); - -const pru_gpo_block = scripting.addModule("/pru_blocks/pru_io_blocks/pru_gpo_block", {}, false); -const pru_gpo_block1 = pru_gpo_block.addInstance(); -const pru_gpo_block2 = pru_gpo_block.addInstance(); - -const group_block = scripting.addModule("/pru_blocks/program_control/group_block", {}, false); -const group_block1 = group_block.addInstance(); - -// Configure blocks -load_constant_block3.$name = "Load_Constant_2"; -load_constant_block3.constant1 = 14; - -load_constant_block4.$name = "Load_Constant_3"; -load_constant_block4.constant1 = 15; - -conditional_block2.$name = "If_Else_1"; -conditional_block2.conditionToCheck = "lessThanEqualtoInput2"; - -pru_gpo_block1.$name = "PRU_GPO_0"; -pru_gpo_block2.$name = "PRU_GPO_1"; - -// Configure group -group_block1.$name = "Group_0"; -group_block1.groupName = "my_group"; -group_block1.$size = [500, 320]; - -// Add blocks inside the group -group_block1.$groupContents = [load_constant_block3, load_constant_block4, conditional_block2, pru_gpo_block1, pru_gpo_block2]; - -// Connect blocks inside the group -scripting.connect(load_constant_block3, "output1", conditional_block2, "input1"); -scripting.connect(load_constant_block4, "output1", conditional_block2, "input2"); -scripting.connect(conditional_block2, "T", pru_gpo_block1, "prev"); -scripting.connect(conditional_block2, "F", pru_gpo_block2, "prev"); - -// Set positions -group_block1.$position = [0, 150]; -load_constant_block3.$position = [60, 40]; -load_constant_block4.$position = [60, 105]; -conditional_block2.$position = [210, 65]; -pru_gpo_block1.$position = [360, 70]; -pru_gpo_block2.$position = [370, 130]; -\\\`\\\`\\\` - -### Calling Groups from main.asm - -\\\`\\\`\\\`asm -; In main.asm - declare and call the group - .ref my_group_start ; Reference the group's start label - -main: - CALL my_group_start ; Execute all blocks in the group - ; Execution automatically returns here - - CALL my_group_start ; Can call multiple times - - halt -\\\`\\\`\\\` - -### Important Notes - -1. **Container Block**: Group is a container - use $groupContents to add blocks inside. - -2. **No Ports**: Group blocks have no input/output ports - they define code sections. - -3. **Label Generation**: A group named "xyz" generates label "xyz_start" in assembly. - -4. **Automatic Return**: Groups automatically add return instruction - no Flow Control needed. - -5. **CALL Macro**: Use CALL (not JMP) to invoke groups so execution returns properly. - -6. **Independent Execution**: Groups only execute when explicitly called from main.asm. - -7. **Return Register**: The register allocator automatically allocates a register for the return address. - ---- - -## Critical Pitfalls (AI Must Read) - -### Pitfall 1: \`groupName\` is SEPARATE from \`$name\` — both must be set -The group block has two distinct name fields: -- \`$name\`: SysConfig instance identifier (e.g., "Group_0") — used internally by SysConfig -- \`groupName\`: generates the assembly label (e.g., "my_group" → \`my_group_start\`) — used in main.asm - -Leaving \`groupName\` empty causes a **build error**: "Group name cannot be empty". -Always set both in the .syscfg file: -\\\`\\\`\\\`javascript -group_block1.$name = "Group_0"; -group_block1.groupName = "my_group"; // REQUIRED - do not omit -\\\`\\\`\\\` - -### Pitfall 2: \`$groupContents\` CANNOT be set via \`changeConfiguration\` MCP tool -The \`changeConfiguration\` tool does not support \`$groupContents\`. It must be set by directly -editing the .syscfg file: -\\\`\\\`\\\`javascript -group_block1.$groupContents = [load_constant_block1, access_look_up_table1]; -\\\`\\\`\\\` -After calling \`changeConfiguration\` and \`save\`, always re-read the .syscfg file to verify -\`$groupContents\` was written correctly and add it manually if missing. - -### Pitfall 3: main.asm MUST \`.include "pru_syscfg.inc"\` to use CALL -\`CALL\` is a macro defined in \`pru_syscfg.inc\` (expands to \`JAL RET_ADDR0, func\`). -It is NOT a native PRU instruction. Without the include, the assembler errors with: -"[E0003] Invalid instruction: CALL". -Add this at the top of main.asm before any group calls: -\\\`\\\`\\\`asm - .include "pru_syscfg.inc" - .ref my_group_start -\\\`\\\`\\\` - -### Pitfall 4: Register allocation SHIFTS when blocks move into a Group -The group return address uses \`R0.w0\` (low 16 bits = \`R0.b0\` + \`R0.b1\`). -To avoid collision, the allocator shifts data registers up (e.g., \`R0.b0\`/\`R0.b1\` → \`R0.b2\`/\`R0.b3\`). -**After any structural change** (adding/removing a group, moving blocks in/out): -1. Rebuild the project -2. Re-read the Register Allocation Summary in the generated \`pru_syscfg.asm\` -3. Update all \`SBBO\` / \`LBBO\` register references in main.asm accordingly -`; -} function getLongDescription() { - return ` + return `NOTE: Before making any assumptions about this block's parameters, behavior, or configuration, always read the docs file at: docs_ai/program_control/group_block.md + ## Group Block (Code Organization Container) ### Purpose @@ -345,7 +174,6 @@ exports = { displayName: "Group", defaultInstanceName: "Group_", longDescription: getLongDescription(), - getAIContext: getAIContext, uiView: "graph", templates: { "/pru_blocks/common/pru_syscfg.asm.xdt": null diff --git a/.metadata/sysconfig/.meta/pru_blocks/program_control/loop_block.syscfg.js b/.metadata/sysconfig/.meta/pru_blocks/program_control/loop_block.syscfg.js index 4d428dd..f5893c4 100644 --- a/.metadata/sysconfig/.meta/pru_blocks/program_control/loop_block.syscfg.js +++ b/.metadata/sysconfig/.meta/pru_blocks/program_control/loop_block.syscfg.js @@ -32,144 +32,10 @@ function getNumOfBytes(value) return 4; } -function getAIContext() { - return getLongDescription() + ` - -## How to Configure (For AI/Scripting) - -This section describes how to programmatically configure the Loop block in a .syscfg file. - -### Adding a Loop Instance - -\\\`\\\`\\\`javascript -const loop_block = scripting.addModule("/pru_blocks/program_control/loop_block", {}, false); -const loop_block1 = loop_block.addInstance(); -\\\`\\\`\\\` - -### Configuration Parameters - -| Parameter | Type | Valid Values | Default | Description | -|-----------|------|--------------|---------|-------------| -| infiniteLoop | Boolean | true, false | false | Enable infinite loop mode | -| loopCount | Integer | 1-65535 (0x1-0xFFFF) | 1 | Number of iterations (hidden if infiniteLoop=true) | -| preInitBlocks | Array | Block $name values inside loop | [] | Blocks to execute once before loop starts | -| $size | Array | [width, height] | [500, 250] | Size of the loop container in pixels | - -### Example Configurations - -**Fixed count loop (100 iterations):** -\\\`\\\`\\\`javascript -loop_block1.$name = "Loop_0"; -loop_block1.infiniteLoop = false; -loop_block1.loopCount = 100; -loop_block1.$size = [500, 290]; -\\\`\\\`\\\` - -**Infinite loop (runs forever):** -\\\`\\\`\\\`javascript -loop_block1.$name = "Main_Loop"; -loop_block1.infiniteLoop = true; -// Note: loopCount is ignored when infiniteLoop is true -\\\`\\\`\\\` - -**Loop with pre-initialization blocks:** -\\\`\\\`\\\`javascript -// Pre-init blocks execute ONCE before the loop starts, not on every iteration -loop_block1.$name = "Loop_0"; -loop_block1.loopCount = 10; -loop_block1.preInitBlocks = ["If_Else_0", "Load_Constant_1", "PRU_GPI_0"]; -\\\`\\\`\\\` - -### Adding Blocks Inside the Loop - -\\\`\\\`\\\`javascript -// Use $groupContents to specify which blocks are inside the loop -loop_block1.$groupContents = [load_constant_block1, load_constant_block2, conditional_block1, pru_gpi_block1, pru_gpi_block2]; -\\\`\\\`\\\` - -### Complete Example with Conditional Inside Loop - -\\\`\\\`\\\`javascript -// Create blocks -const load_constant_block = scripting.addModule("/pru_blocks/data_handling/load_constant_block", {}, false); -const load_constant_block1 = load_constant_block.addInstance(); -const load_constant_block2 = load_constant_block.addInstance(); - -const conditional_block = scripting.addModule("/pru_blocks/program_control/conditional_block", {}, false); -const conditional_block1 = conditional_block.addInstance(); - -const pru_gpi_block = scripting.addModule("/pru_blocks/pru_io_blocks/pru_gpi_block", {}, false); -const pru_gpi_block1 = pru_gpi_block.addInstance(); -const pru_gpi_block2 = pru_gpi_block.addInstance(); - -const loop_block = scripting.addModule("/pru_blocks/program_control/loop_block", {}, false); -const loop_block1 = loop_block.addInstance(); - -// Configure blocks -load_constant_block1.$name = "Load_Constant_0"; -load_constant_block1.constant1 = 5; - -load_constant_block2.$name = "Load_Constant_1"; -load_constant_block2.constant1 = 10; - -conditional_block1.$name = "If_Else_0"; -conditional_block1.conditionToCheck = "notEqualToInput2"; - -pru_gpi_block1.$name = "PRU_GPI_0"; -pru_gpi_block2.$name = "PRU_GPI_1"; - -// Configure loop with pre-init blocks -loop_block1.$name = "Loop_0"; -loop_block1.loopCount = 1; -loop_block1.preInitBlocks = ["If_Else_0", "Load_Constant_1", "PRU_GPI_0"]; -loop_block1.$size = [500, 290]; - -// Add blocks inside the loop -loop_block1.$groupContents = [load_constant_block1, load_constant_block2, conditional_block1, pru_gpi_block1, pru_gpi_block2]; - -// Connect blocks -scripting.connect(load_constant_block1, "output1", conditional_block1, "input1"); -scripting.connect(load_constant_block2, "output1", conditional_block1, "input2"); -scripting.connect(conditional_block1, "T", pru_gpi_block1, "prev"); -scripting.connect(conditional_block1, "F", pru_gpi_block2, "prev"); - -// Set positions -loop_block1.$position = [0, 0]; -load_constant_block1.$position = [105, 55]; -load_constant_block2.$position = [105, 120]; -conditional_block1.$position = [245, 70]; -pru_gpi_block1.$position = [395, 65]; -pru_gpi_block2.$position = [400, 130]; -\\\`\\\`\\\` - -### Connecting to Other Blocks - -\\\`\\\`\\\`javascript -// Connect control flow into the loop -scripting.connect(prev_block, "next", loop_block1, "prev"); - -// Connect control flow out of the loop (only for non-infinite loops) -scripting.connect(loop_block1, "next", next_block, "prev"); -\\\`\\\`\\\` - -### Important Notes - -1. **Container Block**: Loop is a container - use $groupContents to add blocks inside. - -2. **Max Iterations**: Maximum loop count is 65,535 (16-bit limit). Use nested loops for more. - -3. **Infinite Loop**: When infiniteLoop=true, the next port is hidden and loop never exits. - -4. **Pre-Initialization**: Use preInitBlocks with block $name values (as strings) for blocks that should execute once before the loop starts. Useful for initializing accumulators or one-time setup. - -5. **Loop Overhead**: Fixed loops add 2-3 cycles overhead plus 2 cycles per iteration. - -6. **Nested Loops**: Place a Loop block inside another Loop for nested iteration. -`; -} function getLongDescription() { - return ` + return `NOTE: Before making any assumptions about this block's parameters, behavior, or configuration, always read the docs file at: docs_ai/program_control/loop_block.md + ## Loop Block (Repetition Control) ### Purpose @@ -250,10 +116,14 @@ QBA startloop_label ; Unconditional jump back \`\`\` **Performance**: -- Fixed loop overhead: 2-3 cycles (counter initialization) -- Per-iteration overhead: 2 cycles (decrement + branch check) -- Infinite loop overhead: 1 cycle per iteration (unconditional jump) -- Total cycles = overhead + (loop_count × body_cycles) + +*** For finite loop *** +- Initialize loop counter : 1 cycle +- Fixed loop overhead: 1 cycle (counter initialization) +- Total cycles = 2 cycles + (loop_count × body_cycles) + +*** For infinite loop *** +- 1 cycle overhead per iteration **Loop Counter Register**: Automatically sized based on loop count - 1-255: 1 byte register @@ -280,7 +150,7 @@ Blocks execute in the order they are connected via prev/next ports within the lo - Be careful with infinite loops - they never exit - Loop counter uses a register - this register is reserved during loop execution - Nested loops are possible (place a LOOP block inside another LOOP block) -- Loop overhead is minimal (2-3 cycles setup, 2 cycles per iteration) +- Loop overhead is minimal (2-3 cycles setup, 2 cycles per iteration). Note: loop blocks do not emit a end label; break out via Flow Control (jump to next block or sysconfig_generated_end). ### Performance Calculation @@ -288,15 +158,15 @@ Blocks execute in the order they are connected via prev/next ports within the lo - Total cycles = Loop_overhead + (Loop_count × Body_cycles) Where: -- Loop_overhead = 2-3 cycles (counter initialization) +- Loop_overhead = 2-3 cycles (counter initialization + LOOP instruction; 3 for 4-byte counter) - Body_cycles = sum of cycles for all blocks inside loop - Loop_count = number of iterations **Example**: - Loop count: 100 - Body: Load Constant (1 cycle) + Delay(10) (10 cycles) = 11 cycles -- Total = 3 + (100 × 11) = 1103 cycles -- At 200MHz: 1103 × 5ns = 5.515 microseconds +- Total = 2 + (100 × 11) = 1102 cycles +- At 200MHz: 1103 × 5ns = 5.510 microseconds ### Terminology - **Loop**: Programming construct that repeats a sequence of operations @@ -315,7 +185,6 @@ exports = { displayName: "Loop", defaultInstanceName: "Loop_", longDescription: getLongDescription(), - getAIContext: getAIContext, uiView: "graph", templates: { //need to check what can be passed as argument to template file, right now no argument is required diff --git a/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/pru_gpi_block.syscfg.js b/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/pru_gpi_block.syscfg.js index 581800c..cdc90b2 100644 --- a/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/pru_gpi_block.syscfg.js +++ b/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/pru_gpi_block.syscfg.js @@ -46,81 +46,11 @@ function getNumOfBytes(value) return 4; } -function getAIContext() { - return getLongDescription() + ` -## How to Configure (For AI/Scripting) - -This section describes how to programmatically configure the PRU GPI block in a .syscfg file. - -### Adding a PRU GPI Instance - -\\\`\\\`\\\`javascript -const pru_gpi_block = scripting.addModule("/pru_blocks/pru_io_blocks/pru_gpi_block", {}, false); -const gpi1 = pru_gpi_block.addInstance(); -\\\`\\\`\\\` - -### Configuration Parameters - -| Parameter | Type | Valid Values | Default | Description | -|-----------|------|--------------|---------|-------------| -| constant1 | String | "R31, 1 << 0" to "R31, 1 << 19" | "R31, 1 << 0" | PRU GPI pin selection (bit mask) | - -### Valid Values for constant1 - -| Value | Display Name | Description | -|-------|--------------|-------------| -| "R31, 1 << 0" | PRU_GPI_0 | Read input pin 0 | -| "R31, 1 << 1" | PRU_GPI_1 | Read input pin 1 | -| "R31, 1 << 2" | PRU_GPI_2 | Read input pin 2 | -| ... | ... | ... | -| "R31, 1 << 19" | PRU_GPI_19 | Read input pin 19 | - -### Example Configurations - -**Read from PRU_GPI_0:** -\\\`\\\`\\\`javascript -gpi1.$name = "PRU_GPI_0"; -gpi1.constant1 = "R31, 1 << 0"; -\\\`\\\`\\\` - -**Read from PRU_GPI_5 (button input):** -\\\`\\\`\\\`javascript -gpi1.$name = "Button_Input"; -gpi1.constant1 = "R31, 1 << 5"; -\\\`\\\`\\\` - -**Read from PRU_GPI_14 (UART RX line):** -\\\`\\\`\\\`javascript -gpi1.$name = "UART_RX_Monitor"; -gpi1.constant1 = "R31, 1 << 14"; -\\\`\\\`\\\` - -### Connecting to Other Blocks - -\\\`\\\`\\\`javascript -// Connect GPI output to downstream processing block -scripting.connect(gpi1, "output1", process_block, "input1"); - -// Connect control flow -scripting.connect(prev_block, "next", gpi1, "prev"); -scripting.connect(gpi1, "next", next_block, "prev"); -\\\`\\\`\\\` - -### Important Notes - -1. **Output**: The GPI block outputs the masked bit value from R31 (either 0 or non-zero based on pin state). - -2. **Pin Mux**: Physical pin must be configured as PRU GPI in pin mux settings. - -3. **Read-Only**: R31 is a read-only register that reflects current pin states. - -4. **Single Cycle**: Reading takes only 1 PRU cycle. -`; -} function getLongDescription(){ - return ` + return `NOTE: Before making any assumptions about this block's parameters, behavior, or configuration, always read the docs file at: docs_ai/pru_io_blocks/pru_gpi_block.md + ## PRU GPI Block (General Purpose Input) ### Purpose @@ -234,7 +164,6 @@ exports = { displayName: "PRU GPI", defaultInstanceName: `${PRU_USED}_GPI_INSTANCE_`, longDescription: getLongDescription(), - getAIContext: getAIContext, uiView: "graph", templates: { //need to check what can be passed as argument to template file, right now no argument is required diff --git a/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/pru_gpo_block.syscfg.js b/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/pru_gpo_block.syscfg.js index 6ce7c6a..705f36a 100644 --- a/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/pru_gpo_block.syscfg.js +++ b/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/pru_gpo_block.syscfg.js @@ -46,119 +46,11 @@ function getNumOfBytes(value) return 4; } -function getAIContext() { - return getLongDescription() + ` -## How to Configure (For AI/Scripting) -This section describes how to programmatically configure the PRU GPO block in a .syscfg file. - -### Adding a PRU GPO Instance - -\\\`\\\`\\\`javascript -const pru_gpo_block = scripting.addModule("/pru_blocks/pru_io_blocks/pru_gpo_block", {}, false); -const gpo1 = pru_gpo_block.addInstance(); -\\\`\\\`\\\` - -### Configuration Parameters - -| Parameter | Type | Valid Values | Default | Description | -|-----------|------|--------------|---------|-------------| -| constant1 | String | "R30, 0" to "R30, 19" | "R30, 0" | PRU GPO pin selection | -| opCode | String | "SET", "CLR" | "SET" | Output operation (SET=HIGH, CLR=LOW) | - -### Valid Values for constant1 - -| Value | Display Name | Description | -|-------|--------------|-------------| -| "R30, 0" | PRU_GPO_0 | Control output pin 0 | -| "R30, 1" | PRU_GPO_1 | Control output pin 1 | -| "R30, 2" | PRU_GPO_2 | Control output pin 2 | -| ... | ... | ... | -| "R30, 19" | PRU_GPO_19 | Control output pin 19 | - -### Valid Values for opCode - -| Value | Display Name | Description | -|-------|--------------|-------------| -| "SET" | SET SIGNAL | Sets the pin HIGH (logic 1) | -| "CLR" | CLEAR SIGNAL | Sets the pin LOW (logic 0) | - -### Example Configurations - -**Set PRU_GPO_0 HIGH:** -\\\`\\\`\\\`javascript -gpo1.$name = "PRU_GPO_0_Set"; -gpo1.constant1 = "R30, 0"; -gpo1.opCode = "SET"; -\\\`\\\`\\\` - -**Clear PRU_GPO_5 (turn LED OFF):** -\\\`\\\`\\\`javascript -gpo1.$name = "LED_Off"; -gpo1.constant1 = "R30, 5"; -gpo1.opCode = "CLR"; -\\\`\\\`\\\` - -**Assert chip select (active low):** -\\\`\\\`\\\`javascript -gpo1.$name = "CS_Assert"; -gpo1.constant1 = "R30, 10"; -gpo1.opCode = "CLR"; -\\\`\\\`\\\` - -**Deassert chip select:** -\\\`\\\`\\\`javascript -gpo1.$name = "CS_Deassert"; -gpo1.constant1 = "R30, 10"; -gpo1.opCode = "SET"; -\\\`\\\`\\\` - -### Connecting to Other Blocks - -\\\`\\\`\\\`javascript -// GPO is a terminating block - no output connection -// Connect control flow only -scripting.connect(prev_block, "next", gpo1, "prev"); -scripting.connect(gpo1, "next", next_block, "prev"); -\\\`\\\`\\\` - -### Creating a Pulse - -\\\`\\\`\\\`javascript -// Create SET and CLR blocks for pulse generation -const pru_gpo_block = scripting.addModule("/pru_blocks/pru_io_blocks/pru_gpo_block", {}, false); -const gpo_set = pru_gpo_block.addInstance(); -const gpo_clr = pru_gpo_block.addInstance(); - -gpo_set.$name = "Pulse_High"; -gpo_set.constant1 = "R30, 3"; -gpo_set.opCode = "SET"; - -gpo_clr.$name = "Pulse_Low"; -gpo_clr.constant1 = "R30, 3"; -gpo_clr.opCode = "CLR"; - -// Connect in sequence: SET -> delay -> CLR -scripting.connect(gpo_set, "next", delay_block, "prev"); -scripting.connect(delay_block, "next", gpo_clr, "prev"); -\\\`\\\`\\\` - -### Important Notes - -1. **Terminating Block**: GPO has no output port - it only controls physical pins. - -2. **Pin Mux**: Physical pin must be configured as PRU GPO in pin mux settings. - -3. **Single Cycle**: SET/CLR operations take only 1 PRU cycle. - -4. **Persistence**: Pin state persists until explicitly changed by another GPO block. - -5. **Multiple Pins**: Use separate GPO instances to control different pins. -`; -} function getLongDescription(){ - return ` + return `NOTE: Before making any assumptions about this block's parameters, behavior, or configuration, always read the docs file at: docs_ai/pru_io_blocks/pru_gpo_block.md + ## PRU GPO Block (General Purpose Output) ### Purpose @@ -279,7 +171,6 @@ exports = { displayName: "PRU GPO", defaultInstanceName: `${PRU_USED}_GPO_INSTANCE_`, longDescription: getLongDescription(), - getAIContext: getAIContext, uiView: "graph", templates: { //need to check what can be passed as argument to template file, right now no argument is required diff --git a/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/pru_spi_read.syscfg.js b/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/pru_spi_read.syscfg.js index 81bd34c..a9c2ca4 100644 --- a/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/pru_spi_read.syscfg.js +++ b/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/pru_spi_read.syscfg.js @@ -708,97 +708,11 @@ SKIP_BIT_ENTRY_0?: return macroBody; } -function getAIContext() { - return getLongDescription() + ` -## How to Configure (For AI/Scripting) -This section describes how to programmatically configure the SPI Read block in a .syscfg file. - -### Adding a SPI Read Instance - -\\\`\\\`\\\`javascript -const pru_spi_read = scripting.addModule("/pru_blocks/pru_io_blocks/pru_spi_read", {}, false); -const spi_read1 = pru_spi_read.addInstance(); -\\\`\\\`\\\` - -### Configuration Parameters - -| Parameter | Type | Valid Values | Default | Description | -|-----------|------|--------------|---------|-------------| -| Device Mode | String | "controller", "peripheral" | "controller" | SPI role selection | -| SPI Mode | String | "MODE0", "MODE1", "MODE2", "MODE3" | "MODE1" | Clock polarity and phase | -| packetSize | Integer | 8-32 | 8 | Number of bits to read | -| Endiness | String | "most significant bit first", "least significant bit first" | "least significant bit first" | Bit order | -| SCLK Signal | String | "0"-"19" | "0" | GPIO pin for clock | -| SDI Signal | String | "0"-"19" | "1" | GPIO pin for data input | -| CS Signal | String | "0"-"19" | "2" | GPIO pin for chip select | -| sclk high pulse width (in PRU cycles) | Integer | 1-0xFFFFFFFF | 7 | Clock high time (Controller only) | -| sclk low pulse width (in PRU cycles) | Integer | 1-0xFFFFFFFF | 7 | Clock low time (Controller only) | -| CS Setup Time | Integer | 0-10000 | 35 | CS setup time in nanoseconds (Controller only) | -| CS Hold Time | Integer | 0-10000 | 10 | CS hold time in nanoseconds (Controller only) | -| Data Setup Time | Integer | 0-10000 | 0 | Data setup time in nanoseconds, converted to PRU cycles internally (Controller only) | -| CS Filter Cycles | Integer | 1-0xFFFFFFFF | 2 | CS glitch filter cycles (Peripheral only) | - -### Example Configurations - -**SPI Controller Read, MODE1, 8-bit, LSB first:** -\\\`\\\`\\\`javascript -spi_read1.$name = "SPI_Read_0"; -spi_read1["Device Mode"] = "controller"; -spi_read1["SPI Mode"] = "MODE1"; -spi_read1.packetSize = 8; -spi_read1["Endiness"] = "least significant bit first"; -spi_read1["SCLK Signal"] = "0"; -spi_read1["SDI Signal"] = "1"; -spi_read1["CS Signal"] = "2"; -spi_read1["sclk high pulse width (in PRU cycles)"] = 7; -spi_read1["sclk low pulse width (in PRU cycles)"] = 7; -spi_read1["CS Setup Time"] = 35; -spi_read1["CS Hold Time"] = 10; -\\\`\\\`\\\` - -**SPI Peripheral Read, MODE3, 16-bit, MSB first:** -\\\`\\\`\\\`javascript -spi_read1.$name = "SPI_Peripheral_Read"; -spi_read1["Device Mode"] = "peripheral"; -spi_read1["SPI Mode"] = "MODE3"; -spi_read1.packetSize = 16; -spi_read1["Endiness"] = "most significant bit first"; -spi_read1["SCLK Signal"] = "4"; // Input pin for clock -spi_read1["SDI Signal"] = "5"; -spi_read1["CS Signal"] = "6"; // Input pin for CS -spi_read1["CS Filter Cycles"] = 2; -\\\`\\\`\\\` - -### Connecting to Other Blocks - -\\\`\\\`\\\`javascript -// Connect SPI Read output to downstream processing block -scripting.connect(spi_read1, "output1", process_block, "input1"); - -// Connect control flow -scripting.connect(prev_block, "next", spi_read1, "prev"); -scripting.connect(spi_read1, "next", next_block, "prev"); -\\\`\\\`\\\` - -### Important Notes - -1. **Pin Assignment**: In Controller mode, SCLK and CS are outputs (GPO). In Peripheral mode, SCLK and CS are inputs (GPI). SDI is always input (GPI). - -2. **Pin Uniqueness**: All three signals (CS, SCLK, SDI) must use different GPIO pins. - -3. **Minimum Pulse Widths** (Controller mode, per SPI mode): - - MODE0: Min High=4, Min Low=3 - - MODE1: Min High=1, Min Low=6 - - MODE2: Min High=3, Min Low=4 - - MODE3: Min High=6, Min Low=1 - -4. **Read-Only Operation**: This block only reads data from the SPI bus. Use SPI Write or SPI Transfer for sending data. -`; -} function getLongDescription() { - return ` + return `NOTE: Before making any assumptions about this block's parameters, behavior, or configuration, always read the docs file at: docs_ai/pru_io_blocks/pru_spi_read.md + ## PRU SPI Read Block ### Purpose @@ -1000,7 +914,6 @@ exports = { displayName: "PRU SPI Read", defaultInstanceName: `${PRU_USED}_SPI_Read_`, longDescription: getLongDescription(), - getAIContext: getAIContext, uiView: "graph", templates: { //need to check what can be passed as argument to template file, right now no argument is required @@ -1230,8 +1143,8 @@ exports = { // HIGH half overhead: SET SCLK + sub (1) + dataSetup = 2 + dataSetup else if (mode === "MODE1") value = high - 2 - dataSetup; - // MODE2: DATA_SETUP_TIME is not in this half (accounted for in delay_component2) - // LOW half overhead: overhead compensation of 4 = low - 4 + // MODE2: DATA_SETUP_TIME is in the HIGH half (before CLR SCLK sampling edge) + // HIGH half overhead: sub(1) + dataSetup + DELAY_COMPEN_1 → delay_component1 = low - 1 - dataSetup (using low as HIGH pulse base) else if (mode === "MODE2") value = low - 4 ; // MODE3: DATA_SETUP_TIME is now in the LOW half (before SET SCLK sampling edge) @@ -1273,8 +1186,8 @@ exports = { // LOW half overhead: CLR SCLK + bit handling (4) + qbne (1) = 6 else if (mode === "MODE1") value = low - 5; - // MODE2: DATA_SETUP_TIME is in the HIGH half (before CLR SCLK sampling edge) - // HIGH half overhead: overhead compensation of 3 + dataSetup = high - 3 - dataSetup + // MODE2: DATA_SETUP_TIME is in the HIGH half (not here — DELAY_COMPEN_2 is in LOW half) + // LOW half overhead: read SDI(4) + SET SCLK(1) + add/sub(1) + qbne(1) = 7... using base of 3 else if (mode === "MODE2") value = high - 3 - dataSetup; // MODE3: DATA_SETUP_TIME is in the LOW half (not here) diff --git a/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/pru_spi_transfer.syscfg.js b/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/pru_spi_transfer.syscfg.js index 7b95e68..3292f21 100644 --- a/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/pru_spi_transfer.syscfg.js +++ b/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/pru_spi_transfer.syscfg.js @@ -992,104 +992,11 @@ SEND_BIT_LOOP_END?:`; return macroBody; } -function getAIContext() { - return getLongDescription() + ` -## How to Configure (For AI/Scripting) - -This section describes how to programmatically configure the SPI Transfer block in a .syscfg file. - -### Adding a SPI Transfer Instance - -\`\`\`javascript -const pru_spi_transfer = scripting.addModule("/pru_blocks/pru_io_blocks/pru_spi_transfer", {}, false); -const spi1 = pru_spi_transfer.addInstance(); -\`\`\` - -### Configuration Parameters - -| Parameter | Type | Valid Values | Default | Description | -|-----------|------|--------------|---------|-------------| -| Device Mode | String | "controller", "peripheral" | "controller" | SPI role selection | -| SPI Mode | String | "MODE0", "MODE1", "MODE2", "MODE3" | "MODE3" | Clock polarity and phase | -| packetSize | Integer | 8-32 | 32 | Number of bits per transfer | -| Endiness | String | "most significant bit first", "least significant bit first" | "most significant bit first" | Bit order | -| SCLK Signal | String | "0"-"19" | "0" | GPIO pin for clock | -| SDI Signal | String | "0"-"19" | "1" | GPIO pin for data input | -| SDO Signal | String | "0"-"19" | "2" | GPIO pin for data output | -| CS Signal | String | "0"-"19" | "3" | GPIO pin for chip select | -| sclk high pulse width (in PRU cycles) | Integer | 1-0xFFFFFFFF | 9 | Clock high time (Controller only) | -| sclk low pulse width (in PRU cycles) | Integer | 1-0xFFFFFFFF | 7 | Clock low time (Controller only) | -| CS Setup Time | Integer | 0-10000 | 35 | CS setup time in nanoseconds (Controller only) | -| CS Hold Time | Integer | 0-10000 | 10 | CS hold time in nanoseconds (Controller only) | -| Data Setup Time | Integer | 0-10000 | 0 | Data setup time in nanoseconds, converted to PRU cycles internally (Controller only) | -| CS Filter Cycles | Integer | 1-0xFFFFFFFF | 2 | CS glitch filter cycles (Peripheral only) | - -### Example Configurations - -**SPI Controller, MODE3, 8-bit, MSB first:** -\`\`\`javascript -spi1.$name = "SPI_Controller_0"; -spi1["Device Mode"] = "controller"; -spi1["SPI Mode"] = "MODE3"; -spi1.packetSize = 8; -spi1["Endiness"] = "most significant bit first"; -spi1["SCLK Signal"] = "0"; -spi1["SDI Signal"] = "1"; -spi1["SDO Signal"] = "2"; -spi1["CS Signal"] = "3"; -spi1["sclk high pulse width (in PRU cycles)"] = 13; -spi1["sclk low pulse width (in PRU cycles)"] = 11; -spi1["CS Setup Time"] = 35; -spi1["CS Hold Time"] = 10; -\`\`\` - -**SPI Peripheral, MODE0, 32-bit, LSB first:** -\`\`\`javascript -spi1.$name = "SPI_Peripheral_0"; -spi1["Device Mode"] = "peripheral"; -spi1["SPI Mode"] = "MODE0"; -spi1.packetSize = 32; -spi1["Endiness"] = "least significant bit first"; -spi1["SCLK Signal"] = "4"; // Input pin for clock -spi1["SDI Signal"] = "5"; -spi1["SDO Signal"] = "6"; -spi1["CS Signal"] = "7"; // Input pin for CS -spi1["CS Filter Cycles"] = 2; -\`\`\` - -### Connecting to Other Blocks - -\`\`\`javascript -// Connect data source to SPI input (data to transmit) -scripting.connect(load_constant1, "output1", spi1, "input1"); - -// Connect SPI output to downstream block (received data) -scripting.connect(spi1, "output1", process_block, "input1"); - -// Connect control flow -scripting.connect(prev_block, "next", spi1, "prev"); -scripting.connect(spi1, "next", next_block, "prev"); -\`\`\` - -### Important Notes - -1. **Pin Assignment**: In Controller mode, SCLK and CS are outputs (GPO). In Peripheral mode, SCLK and CS are inputs (GPI). - -2. **Pin Uniqueness**: All four signals (CS, SCLK, SDI, SDO) must use different GPIO pins. - -3. **Minimum Pulse Widths** (Controller mode, per SPI mode): - - MODE0: Min High=4, Min Low=6 - - MODE1: Min High=2, Min Low=6 - - MODE2: Min High=6, Min Low=4 - - MODE3: Min High=6, Min Low=2 - -4. **Full-Duplex Operation**: This block simultaneously sends and receives data. Connect both input (transmit data) and use output (receive data) for full-duplex communication. -`; -} function getLongDescription() { - return ` + return `NOTE: Before making any assumptions about this block's parameters, behavior, or configuration, always read the docs file at: docs_ai/pru_io_blocks/pru_spi_transfer.md + ## PRU SPI Transfer Block ### Purpose @@ -1260,7 +1167,6 @@ exports = { displayName: "PRU SPI Transfer", defaultInstanceName: `${PRU_USED}_SPI_Transfer_`, longDescription: getLongDescription(), - getAIContext: getAIContext, uiView: "graph", templates: { "/pru_blocks/common/pru_syscfg.asm.xdt": null diff --git a/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/pru_spi_write.syscfg.js b/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/pru_spi_write.syscfg.js index c1ac2e8..f7f3f83 100644 --- a/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/pru_spi_write.syscfg.js +++ b/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/pru_spi_write.syscfg.js @@ -767,99 +767,11 @@ SEND_BIT_LOOP_END?:`; return macroBody; } -function getAIContext() { - return getLongDescription() + ` -## How to Configure (For AI/Scripting) -This section describes how to programmatically configure the SPI Write block in a .syscfg file. - -### Adding a SPI Write Instance - -\\\`\\\`\\\`javascript -const pru_spi_write = scripting.addModule("/pru_blocks/pru_io_blocks/pru_spi_write", {}, false); -const spi_write1 = pru_spi_write.addInstance(); -\\\`\\\`\\\` - -### Configuration Parameters - -| Parameter | Type | Valid Values | Default | Description | -|-----------|------|--------------|---------|-------------| -| Device Mode | String | "controller", "peripheral" | "controller" | SPI role selection | -| SPI Mode | String | "MODE0", "MODE1", "MODE2", "MODE3" | "MODE1" | Clock polarity and phase | -| packetSize | Integer | 8-32 | 8 | Number of bits to write | -| Endiness | String | "most significant bit first", "least significant bit first" | "least significant bit first" | Bit order | -| SCLK Signal | String | "0"-"19" | "0" | GPIO pin for clock | -| SDO Signal | String | "0"-"19" | "1" | GPIO pin for data output | -| CS Signal | String | "0"-"19" | "2" | GPIO pin for chip select | -| sclk high pulse width (in PRU cycles) | Integer | 1-0xFFFFFFFF | 7 | Clock high time (Controller only) | -| sclk low pulse width (in PRU cycles) | Integer | 1-0xFFFFFFFF | 7 | Clock low time (Controller only) | -| CS Setup Time | Integer | 0-10000 | 10 | CS setup time in nanoseconds (Controller only) | -| CS Hold Time | Integer | 0-10000 | 10 | CS hold time in nanoseconds (Controller only) | -| Data Setup Time | Integer | 0-10000 | 0 | Data setup time in nanoseconds, converted to PRU cycles internally (Controller only) | -| CS Filter Cycles | Integer | 1-0xFFFFFFFF | 2 | CS glitch filter cycles (Peripheral only) | - -### Example Configurations - -**SPI Controller Write, MODE1, 8-bit, LSB first:** -\\\`\\\`\\\`javascript -spi_write1.$name = "SPI_Write_0"; -spi_write1["Device Mode"] = "controller"; -spi_write1["SPI Mode"] = "MODE1"; -spi_write1.packetSize = 8; -spi_write1["Endiness"] = "least significant bit first"; -spi_write1["SCLK Signal"] = "0"; -spi_write1["SDO Signal"] = "1"; -spi_write1["CS Signal"] = "2"; -spi_write1["sclk high pulse width (in PRU cycles)"] = 7; -spi_write1["sclk low pulse width (in PRU cycles)"] = 7; -spi_write1["CS Setup Time"] = 10; -spi_write1["CS Hold Time"] = 10; -\\\`\\\`\\\` - -**SPI Peripheral Write, MODE0, 32-bit, MSB first:** -\\\`\\\`\\\`javascript -spi_write1.$name = "SPI_Peripheral_Write"; -spi_write1["Device Mode"] = "peripheral"; -spi_write1["SPI Mode"] = "MODE0"; -spi_write1.packetSize = 32; -spi_write1["Endiness"] = "most significant bit first"; -spi_write1["SCLK Signal"] = "4"; // Input pin for clock -spi_write1["SDO Signal"] = "5"; // Output pin for data -spi_write1["CS Signal"] = "6"; // Input pin for CS -spi_write1["CS Filter Cycles"] = 2; -\\\`\\\`\\\` - -### Connecting to Other Blocks - -\\\`\\\`\\\`javascript -// Connect data source to SPI Write input (data to transmit) -scripting.connect(load_constant1, "output1", spi_write1, "input1"); - -// Connect control flow -scripting.connect(prev_block, "next", spi_write1, "prev"); -scripting.connect(spi_write1, "next", next_block, "prev"); -\\\`\\\`\\\` - -### Important Notes - -1. **Pin Assignment**: In Controller mode, SCLK and CS are outputs (GPO). In Peripheral mode, SCLK and CS are inputs (GPI). SDO is always output (GPO). - -2. **Pin Uniqueness**: All three signals (CS, SCLK, SDO) must use different GPIO pins. - -3. **Minimum Pulse Widths** (Controller mode, per SPI mode): - - MODE0: Min High=2, Min Low=6 - - MODE1: Min High=4, Min Low=3 - - MODE2: Min High=6, Min Low=1 - - MODE3: Min High=3, Min Low=4 - -4. **Input Required**: This block requires a data input connection. Connect a Load Constant block or other data source to input1. - -5. **Write-Only Operation**: This block only writes data to the SPI bus. Use SPI Read or SPI Transfer for receiving data. -`; -} function getLongDescription() { - return ` + return `NOTE: Before making any assumptions about this block's parameters, behavior, or configuration, always read the docs file at: docs_ai/pru_io_blocks/pru_spi_write.md + ## PRU SPI Write Block ### Purpose @@ -1025,7 +937,6 @@ exports = { displayName: "PRU SPI Write", defaultInstanceName: `${PRU_USED}_SPI_Write_`, longDescription: getLongDescription(), - getAIContext: getAIContext, uiView: "graph", templates: { //need to check what can be passed as argument to template file, right now no argument is required diff --git a/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/uart_config.syscfg.js b/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/uart_config.syscfg.js index e435bab..1c98329 100644 --- a/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/uart_config.syscfg.js +++ b/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/uart_config.syscfg.js @@ -342,7 +342,8 @@ ${txIsLSB } function getLongDescription() { - return ` + return `NOTE: Before making any assumptions about this block's parameters, behavior, or configuration, always read the docs file at: docs_ai/pru_io_blocks/uart_config.md + ## UART Config (Combined TX + RX Hardware Configuration) ### Purpose diff --git a/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/uart_rx_op.syscfg.js b/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/uart_rx_op.syscfg.js index 68516c1..158164b 100644 --- a/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/uart_rx_op.syscfg.js +++ b/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/uart_rx_op.syscfg.js @@ -327,7 +327,8 @@ no_stop_carry?: } function getLongDescription() { - return ` + return `NOTE: Before making any assumptions about this block's parameters, behavior, or configuration, always read the docs file at: docs_ai/pru_io_blocks/uart_rx_op.md + ## UART RX Op (Per-Reception Operation) ### Purpose @@ -386,98 +387,12 @@ allocator needs to know at design time. `; } -function getAIContext() { - return getLongDescription() + ` -## How to Configure (For AI/Scripting) - -This section describes how to programmatically configure the UART RX Op block in a .syscfg file. - -**CRITICAL**: The UART RX Op block requires a paired \`UART Config\` block with RX enabled. -The op block reads all RX parameters (channel, baud rate, oversample, bit order, start bit polarity) -from the config block automatically. Only \`rxFrameSize\` is set on the op block itself. - -### Step 1 — Add and configure a UART Config block (RX enabled) - -\`\`\`javascript -const uart_config = scripting.addModule("/pru_blocks/pru_io_blocks/uart_config", {}, false); -const uart_config1 = uart_config.addInstance(); -uart_config1.$name = "PRU_UART_CONFIG_0"; -uart_config1.enableTX = false; // TX-only or TX+RX — set as needed -uart_config1.enableRX = true; -uart_config1.rxChannel = 2; // Channel 2 (GPI11 = PERIF2_IN) -uart_config1.rxClockSource = 0; // 192 MHz (UART_CLK) -uart_config1.rxBaudRate = 12; // 12 MHz -uart_config1.rxOversampleSize = 7; // 8x oversample -uart_config1.rxStartBitPolarity = 1; // Rising edge -uart_config1.rxBitSwap = true; // LSB first (standard UART) -\`\`\` - -### Step 2 — Add and configure the UART RX Op block - -\`\`\`javascript -const uart_rx_op = scripting.addModule("/pru_blocks/pru_io_blocks/uart_rx_op", {}, false); -const uart_rx_op1 = uart_rx_op.addInstance(); -uart_rx_op1.$name = "PRU_UART_RX_OP_0"; -uart_rx_op1.rxFrameSize = 18; // 16 data bits + start + stop = 18 -uart_rx_op1.uartConfig = uart_config1; // Link to config block -\`\`\` - -### Step 3 — Connect control flow and data - -\`\`\`javascript -// Control flow: config must run before op -scripting.connect(uart_config1, "next", uart_rx_op1, "prev"); - -// Data: connect op output to downstream block -scripting.connect(uart_rx_op1, "output1", next_block, "input1"); - -// Control flow out of op -scripting.connect(uart_rx_op1, "next", next_block, "prev"); -\`\`\` - -### Configuration Parameters -| Parameter | Type | Valid Values | Default | Description | -|-----------|------|--------------|---------|-------------| -| rxFrameSize | Integer | 3–64 | 10 | Total frame bits (dataBits + 2). Values > 32 use 64-bit output port | - -All other RX parameters (channel, baud rate, oversample, bit order, start bit polarity) are -read from the paired \`UART Config\` block — do not duplicate them here. - -### Output Port Type by Frame Size - -| rxFrameSize | Data Bits | Output Port | Notes | -|-------------|-----------|-------------|-------| -| 3–32 | 1–30 | 32-bit (output32) | Single register output | -| 33–64 | 31–62 | 64-bit (output64) | Two consecutive registers; downstream block must accept 64-bit input | - -### Common Frame Sizes - -| Protocol | Data Bits | rxFrameSize | -|----------|-----------|-------------| -| Standard UART 8-bit | 8 | 10 | -| UART 16-bit payload | 16 | 18 | -| UART 24-bit payload | 24 | 26 | -| UART 30-bit payload | 30 | 32 | -| UART 31-bit payload (extended) | 31 | 33 | - -### Important Notes - -1. **UART Config must appear before UART RX Op** in the control flow (connect config "next" to op "prev"). - -2. **rxFrameSize > 32 activates extended mode** — output port becomes 64-bit. Downstream blocks must be wired to accept a 64-bit input. - -3. **No peripheral register writes in this block** — only rx_en assert/de-assert and the bit polling loop. All register setup is in \`UART Config\`. - -4. **uartConfig linkage is mandatory** — always set \`uart_rx_op1.uartConfig = uart_config1\` or the block will error during validation. -`; -} exports = { displayName: "PRU UART RX Op", defaultInstanceName: "PRU_UART_RX_OP_", longDescription: getLongDescription(), - getAIContext: getAIContext, uiView: "graph", templates: { "/pru_blocks/common/pru_syscfg.asm.xdt": null diff --git a/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/uart_tx_op.syscfg.js b/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/uart_tx_op.syscfg.js index ffd3b71..ef64ae0 100644 --- a/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/uart_tx_op.syscfg.js +++ b/.metadata/sysconfig/.meta/pru_blocks/pru_io_blocks/uart_tx_op.syscfg.js @@ -672,7 +672,8 @@ function validate(inst, report) { } function getLongDescription() { - return ` + return `NOTE: Before making any assumptions about this block's parameters, behavior, or configuration, always read the docs file at: docs_ai/pru_io_blocks/uart_tx_op.md + ## UART TX Op (Per-Transmission Operation) ### Purpose @@ -736,102 +737,12 @@ needs to know at design time. `; } -function getAIContext() { - return getLongDescription() + ` -## How to Configure (For AI/Scripting) - -This section describes how to programmatically configure the UART TX Op block in a .syscfg file. - -**CRITICAL**: The UART TX Op block requires a paired \`UART Config\` block with TX enabled. -The op block reads all TX parameters (channel, baud rate, bit order, start/stop polarity) -from the config block automatically. Only \`Data Bits\` is set on the op block itself. - -### Step 1 — Add and configure a UART Config block (TX enabled) - -\`\`\`javascript -const uart_config = scripting.addModule("/pru_blocks/pru_io_blocks/uart_config", {}, false); -const uart_config1 = uart_config.addInstance(); -uart_config1.$name = "PRU_UART_CONFIG_0"; -uart_config1.enableTX = true; -uart_config1.enableRX = false; // TX-only or TX+RX — set as needed -uart_config1.txChannel = 0; // Channel 0 (GPO0=CLK, GPO1=DOUT, GPO2=OE) -uart_config1.txClockSource = 0; // 192 MHz (UART_CLK) -uart_config1.txBaudRate = 12; // 12 MHz -uart_config1.txStartBitPolarity = 1; // Start bit = 1 (high) -uart_config1.txStopBitPolarity = 0; // Stop bit = 0 (low) -uart_config1.txBitSwap = true; // LSB first (standard UART) -\`\`\` - -### Step 2 — Add and configure the UART TX Op block - -\`\`\`javascript -const uart_tx_op = scripting.addModule("/pru_blocks/pru_io_blocks/uart_tx_op", {}, false); -const uart_tx_op1 = uart_tx_op.addInstance(); -uart_tx_op1.$name = "PRU_UART_TX_OP_0"; -uart_tx_op1.dataBits = 16; // 16 data payload bits -uart_tx_op1.uartConfig = uart_config1; // Link to config block -\`\`\` - -### Step 3 — Connect control flow and data - -\`\`\`javascript -// Control flow: config must run before op -scripting.connect(uart_config1, "next", uart_tx_op1, "prev"); - -// Data: connect upstream data source to op input -scripting.connect(data_source_block, "output1", uart_tx_op1, "input1"); - -// Control flow out of op -scripting.connect(uart_tx_op1, "next", next_block, "prev"); -\`\`\` - -### Configuration Parameters - -| Parameter | Type | Valid Values | Default | Description | -|-----------|------|--------------|---------|-------------| -| dataBits | Integer | 1–62 | 8 | Number of data payload bits. Determines input port type (32-bit vs 64-bit) | -All other TX parameters (channel, baud rate, bit order, start/stop polarity) are -read from the paired \`UART Config\` block — do not duplicate them here. - -### Input Port Type by Data Bits - -| dataBits | Input Port | Notes | -|----------|------------|-------| -| 1–32 | 32-bit (input32) | Single register input | -| 33–62 | 64-bit (input64) | Two consecutive registers; upstream block must produce 64-bit output | - -### Common Data Bit Configurations - -| Protocol | Data Bits | Frame Bits (dataBits+2) | Mode | -|----------|-----------|------------------------|------| -| Standard UART 8-bit | 8 | 10 | Single-shot | -| 16-bit payload | 16 | 18 | Single-shot | -| 24-bit payload | 24 | 26 | Single-shot | -| 29-bit payload | 29 | 31 | Single-shot (max single-shot) | -| 30-bit payload | 30 | 32 | Specific-bit mode | -| 32-bit payload | 32 | 34 | Specific-bit mode | -| 33-bit payload | 33 | 35 | Continuous mode | - -### Important Notes - -1. **UART Config must appear before UART TX Op** in the control flow (connect config "next" to op "prev"). - -2. **dataBits > 32 activates continuous mode** — input port becomes 64-bit. The upstream data source block must produce a 64-bit output. - -3. **No peripheral register writes in this block** — only per-command reinit, frame construction, FIFO load, and TX trigger. All register setup is in \`UART Config\`. - -4. **uartConfig linkage is mandatory** — always set \`uart_tx_op1.uartConfig = uart_config1\` or the block will error during validation. - -5. **All UART TX Op instances must use the same dataBits value** — \`UART Config\` uses the first instance's dataBits for TX_FRAME_SIZE configuration. Mismatched instances will generate incorrect assembly. -`; -} exports = { displayName: "PRU UART TX Op", defaultInstanceName: "PRU_UART_TX_OP_", longDescription: getLongDescription(), - getAIContext: getAIContext, uiView: "graph", templates: { "/pru_blocks/common/pru_syscfg.asm.xdt": null diff --git a/.metadata/sysconfig/.meta/pru_blocks/utils/access_look_up_table.syscfg.js b/.metadata/sysconfig/.meta/pru_blocks/utils/access_look_up_table.syscfg.js index 8e0e7b6..56bdeaf 100644 --- a/.metadata/sysconfig/.meta/pru_blocks/utils/access_look_up_table.syscfg.js +++ b/.metadata/sysconfig/.meta/pru_blocks/utils/access_look_up_table.syscfg.js @@ -100,72 +100,11 @@ function getMacro(pruInstructionMacro, opCode) { return macroBody; } -function getAIContext() { - return getLongDescription() + ` -## How to Configure (For AI/Scripting) -This section describes how to programmatically configure the Access Lookup Table block in a .syscfg file. - -### Adding an Access Lookup Table Instance - -\\\`\\\`\\\`javascript -const access_look_up_table = scripting.addModule("/pru_blocks/utils/access_look_up_table", {}, false); -const access_lut1 = access_look_up_table.addInstance(); -\\\`\\\`\\\` - -### Configuration Parameters - -| Parameter | Type | Valid Values | Default | Description | -|-----------|------|--------------|---------|-------------| -| lutReference | String | Name of a Lookup Table instance | "" | Which Lookup Table to read from | - -### Example Configurations - -**Read from a lookup table:** -\\\`\\\`\\\`javascript -// First create the Lookup Table -const look_up_table = scripting.addModule("/pru_blocks/utils/look_up_table", {}, false); -const lut1 = look_up_table.addInstance(); -lut1.$name = "Sine_Table"; -lut1.tableSize = 256; -lut1.dataType = "ushort"; -lut1.initPattern = "sequential"; - -// Then create Access Lookup Table to read from it -access_lut1.$name = "Read_Sine"; -access_lut1.lutReference = "Sine_Table"; -\\\`\\\`\\\` - -### Connecting to Other Blocks - -\\\`\\\`\\\`javascript -// Connect index source to input (index port) -scripting.connect(load_constant1, "output1", access_lut1, "input1"); - -// Connect output to downstream block -scripting.connect(access_lut1, "output1", uart_tx1, "input1"); - -// Connect control flow -scripting.connect(prev_block, "next", access_lut1, "prev"); -scripting.connect(access_lut1, "next", next_block, "prev"); -\\\`\\\`\\\` - -### Important Notes - -1. **Requires Lookup Table**: A Lookup Table block must exist and be referenced by lutReference. - -2. **Index Input**: Connect a block that provides the index value (0 to tableSize-1) to input1. - -3. **Output Size**: Automatically matches the referenced Lookup Table's dataType (1, 2, or 4 bytes). - -4. **Bounds Checking**: Validation warns if constant index is out of bounds. Runtime bounds checking is not performed. - -5. **Performance**: 5 PRU cycles total (2 for LDI32 + 3 for LBBO). -`; -} function getLongDescription() { - return ` + return `NOTE: Before making any assumptions about this block's parameters, behavior, or configuration, always read the docs file at: docs_ai/utils/access_look_up_table.md + ## Access Lookup Table Block ### Purpose @@ -205,7 +144,6 @@ exports = { displayName: "Access Lookup Table", defaultInstanceName: "Access_Lookup_Table_", longDescription: getLongDescription(), - getAIContext: getAIContext, uiView: "graph", templates: { "/pru_blocks/common/pru_syscfg.asm.xdt": null diff --git a/.metadata/sysconfig/.meta/pru_blocks/utils/data_splitter.syscfg.js b/.metadata/sysconfig/.meta/pru_blocks/utils/data_splitter.syscfg.js index 151a646..1664298 100644 --- a/.metadata/sysconfig/.meta/pru_blocks/utils/data_splitter.syscfg.js +++ b/.metadata/sysconfig/.meta/pru_blocks/utils/data_splitter.syscfg.js @@ -24,7 +24,8 @@ function getMacro(pruInstructionMacro, opCode) { } function getLongDescription() { - return ` + return `NOTE: Before making any assumptions about this block's parameters, behavior, or configuration, always read the docs file at: docs_ai/utils/data_splitter.md + ## Data Splitter Block ### Purpose diff --git a/.metadata/sysconfig/.meta/pru_blocks/utils/delay_block.syscfg.js b/.metadata/sysconfig/.meta/pru_blocks/utils/delay_block.syscfg.js index 864b2ad..7a05a35 100644 --- a/.metadata/sysconfig/.meta/pru_blocks/utils/delay_block.syscfg.js +++ b/.metadata/sysconfig/.meta/pru_blocks/utils/delay_block.syscfg.js @@ -48,68 +48,11 @@ endloop?:`; return macroBody; } -function getAIContext() { - return getLongDescription() + ` -## How to Configure (For AI/Scripting) - -This section describes how to programmatically configure the Delay block in a .syscfg file. - -### Adding a Delay Instance - -\\\`\\\`\\\`javascript -const delay_block = scripting.addModule("/pru_blocks/utils/delay_block", {}, false); -const delay1 = delay_block.addInstance(); -\\\`\\\`\\\` - -### Configuration Parameters - -| Parameter | Type | Valid Values | Default | Description | -|-----------|------|--------------|---------|-------------| -| delayCount | Integer | 1-255 | 1 | Number of PRU clock cycles to wait | - -### Example Configurations - -**Short delay (50ns at 200MHz):** -\\\`\\\`\\\`javascript -delay1.$name = "Delay_Short"; -delay1.delayCount = 10; // 10 cycles = 50ns -\\\`\\\`\\\` - -**Medium delay (500ns at 200MHz):** -\\\`\\\`\\\`javascript -delay1.$name = "Delay_Medium"; -delay1.delayCount = 100; // 100 cycles = 500ns -\\\`\\\`\\\` - -**Maximum single-block delay (1.275us at 200MHz):** -\\\`\\\`\\\`javascript -delay1.$name = "Delay_Max"; -delay1.delayCount = 255; // 255 cycles = 1.275us -\\\`\\\`\\\` - -### Connecting to Other Blocks - -\\\`\\\`\\\`javascript -// Connect control flow (Delay is a pass-through block) -scripting.connect(prev_block, "next", delay1, "prev"); -scripting.connect(delay1, "next", next_block, "prev"); -\\\`\\\`\\\` - -### Important Notes - -1. **Maximum Delay**: Single Delay block limited to 255 cycles. Use Loop block for longer delays. - -2. **Timing**: At 200MHz PRU clock, 1 cycle = 5ns. delayCount of 200 = 1 microsecond. - -3. **Pass-through**: Delay block has no data ports - it only introduces timing delay in the control flow. - -4. **Single Cycle Special Case**: When delayCount=1, generates single NOP instruction instead of loop. -`; -} function getLongDescription() { - return ` + return `NOTE: Before making any assumptions about this block's parameters, behavior, or configuration, always read the docs file at: docs_ai/utils/delay_block.md + ## Delay Block ### Purpose @@ -201,7 +144,6 @@ exports = { displayName: "Delay", defaultInstanceName: "Delay_", longDescription: getLongDescription(), - getAIContext: getAIContext, uiView: "graph", templates: { //need to check what can be passed as argument to template file, right now no argument is required diff --git a/.metadata/sysconfig/.meta/pru_blocks/utils/label.syscfg.js b/.metadata/sysconfig/.meta/pru_blocks/utils/label.syscfg.js index d4a06b1..c5c35f4 100644 --- a/.metadata/sysconfig/.meta/pru_blocks/utils/label.syscfg.js +++ b/.metadata/sysconfig/.meta/pru_blocks/utils/label.syscfg.js @@ -1,42 +1,8 @@ -function getAIContext() { - return getLongDescription() + ` - -## How to Configure (For AI/Scripting) -This section describes how to programmatically configure the Label block in a .syscfg file. - -### Adding a Label Instance - -\\\`\\\`\\\`javascript -const label_block = scripting.addModule("/pru_blocks/utils/label", {}, false); -const label1 = label_block.addInstance(); -\\\`\\\`\\\` - -### Configuration Parameters - -| Parameter | Type | Valid Values | Default | Description | -|-----------|------|--------------|---------|-------------| -| $name | String | Any valid identifier | "Label_0" | Instance name (displayed as label text) | - -### Example Configuration - -**Add a documentation label:** -\\\`\\\`\\\`javascript -label1.$name = "UART_TX_Section"; -\\\`\\\`\\\` - -### Important Notes - -1. **No Code Generation**: Label blocks are purely for documentation and generate no assembly code. - -2. **No Ports**: Labels have no input/output ports and cannot be connected to other blocks. - -3. **Visual Only**: Labels appear only in the SysConfig GUI and don't affect PRU execution. -`; -} function getLongDescription() { - return ` + return `NOTE: Before making any assumptions about this block's parameters, behavior, or configuration, always read the docs file at: docs_ai/utils/label.md + ## Label Block ### Purpose diff --git a/.metadata/sysconfig/.meta/pru_blocks/utils/look_up_table.syscfg.js b/.metadata/sysconfig/.meta/pru_blocks/utils/look_up_table.syscfg.js index c040dfe..7ea53e8 100644 --- a/.metadata/sysconfig/.meta/pru_blocks/utils/look_up_table.syscfg.js +++ b/.metadata/sysconfig/.meta/pru_blocks/utils/look_up_table.syscfg.js @@ -61,107 +61,11 @@ function getMacro(pruInstructionMacro, opCode) { // This block doesn't generate any runtime code, only data section return "0"; } -function getAIContext() { - return getLongDescription() + ` - -## How to Configure (For AI/Scripting) - -This section describes how to programmatically configure the Lookup Table block in a .syscfg file. - -### Adding a Lookup Table Instance - -\\\`\\\`\\\`javascript -const look_up_table = scripting.addModule("/pru_blocks/utils/look_up_table", {}, false); -const lut1 = look_up_table.addInstance(); -\\\`\\\`\\\` - -### Configuration Parameters - -| Parameter | Type | Valid Values | Default | Description | -|-----------|------|--------------|---------|-------------| -| tableSize | Integer | 1-65536 | 16 | Number of entries in the table | -| dataType | String | "byte", "ushort", "uint" | "byte" | Data type for each entry | -| importMethod | String | "manual", "json_paste", "json_file" | "manual" | How to input data | -| initPattern | String | "manual", "sequential", "zeros", "ones", "custom" | "sequential" | Pattern for auto-generating data | -| customValue | Integer | Depends on dataType | 0 | Fill value when initPattern="custom" | -| tableData | String | Comma-separated values | "0,1,2,..." | The actual table data | - -### Valid Values for dataType - -| Value | Display Name | Range | Bytes per Entry | -|-------|--------------|-------|-----------------| -| "byte" | 8-bit (0-255) | 0-255 | 1 | -| "ushort" | 16-bit (0-65535) | 0-65535 | 2 | -| "uint" | 32-bit | 0-4294967295 | 4 | - -### Valid Values for initPattern - -| Value | Display Name | Description | -|-------|--------------|-------------| -| "manual" | Manual Entry | Edit tableData directly | -| "sequential" | Sequential (0, 1, 2, ...) | Auto-fill with 0, 1, 2, ... | -| "zeros" | All Zeros | Fill with 0 | -| "ones" | All Ones | Fill with 0xFF/0xFFFF/0xFFFFFFFF | -| "custom" | Fill With Custom Value | Fill with customValue | - -### Example Configurations - -**Small sequential table (16 bytes):** -\\\`\\\`\\\`javascript -lut1.$name = "Lookup_Table_0"; -lut1.tableSize = 16; -lut1.dataType = "byte"; -lut1.initPattern = "sequential"; -// tableData auto-generates: "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15" -\\\`\\\`\\\` - -**Sine wave lookup table (256 entries, 16-bit):** -\\\`\\\`\\\`javascript -lut1.$name = "Sine_Table"; -lut1.tableSize = 256; -lut1.dataType = "ushort"; -lut1.initPattern = "manual"; -lut1.tableData = "32768, 33572, 34376, ..."; // Pre-computed sine values -\\\`\\\`\\\` - -**Custom fill value:** -\\\`\\\`\\\`javascript -lut1.$name = "Init_Buffer"; -lut1.tableSize = 64; -lut1.dataType = "uint"; -lut1.initPattern = "custom"; -lut1.customValue = 0xDEADBEEF; -\\\`\\\`\\\` - -### Connecting to Other Blocks - -\\\`\\\`\\\`javascript -// Lookup Table is data-only, connect Access Lookup Table to read from it -const access_lut = scripting.addModule("/pru_blocks/utils/access_look_up_table", {}, false); -const access1 = access_lut.addInstance(); -access1.lutReference = lut1.$name; // Reference this lookup table - -// Connect index source to Access Lookup Table -scripting.connect(index_block, "output1", access1, "input1"); -\\\`\\\`\\\` - -### Important Notes - -1. **Data Only**: Lookup Table block defines data storage - use Access Lookup Table to read values. - -2. **Memory Size**: Total memory = tableSize × bytes per entry. Maximum DMEM is 8KB per PRU. - -3. **R5F Initialization**: Data is written to PRU DMEM by the R5F core before PRU starts. - -4. **JSON Import**: For large tables, use importMethod="json_paste" or "json_file" with format: - \\\`\\\`\\\`json - { "values": [0, 1, 2, ...], "dataType": "byte" } - \\\`\\\`\\\` -`; -} + function getLongDescription() { - return ` + return `NOTE: Before making any assumptions about this block's parameters, behavior, or configuration, always read the docs file at: docs_ai/utils/look_up_table.md + ## Lookup Table Block ### Purpose @@ -244,7 +148,6 @@ exports = { displayName: "Lookup Table", defaultInstanceName: "Lookup_Table_", longDescription: getLongDescription(), - getAIContext: getAIContext, uiView: "graph", templates: { "/pru_blocks/common/pru_syscfg.asm.xdt": null diff --git a/.metadata/sysconfig/.meta/pru_blocks/utils/memory_access_block.syscfg.js b/.metadata/sysconfig/.meta/pru_blocks/utils/memory_access_block.syscfg.js index 7b87d9a..3ae5882 100644 --- a/.metadata/sysconfig/.meta/pru_blocks/utils/memory_access_block.syscfg.js +++ b/.metadata/sysconfig/.meta/pru_blocks/utils/memory_access_block.syscfg.js @@ -160,92 +160,11 @@ function getMacro(pruInstructionMacro, opCode) { return pruInstructionMacro; } -function getAIContext() { - return getLongDescription() + ` -## How to Configure (For AI/Scripting) - -This section describes how to programmatically configure the Memory Access block in a .syscfg file. - -### Adding a Memory Access Instance - -\\\`\\\`\\\`javascript -const memory_load_block = scripting.addModule("/pru_blocks/data_handling/memory_load_block", {}, false); -const mem_access1 = memory_load_block.addInstance(); -\\\`\\\`\\\` - -### Configuration Parameters - -| Parameter | Type | Valid Values | Default | Description | -|-----------|------|--------------|---------|-------------| -| operationMode | String | "read", "write" | "read" | Read (LBBO) or Write (SBBO) operation | -| symbolSelect | String | Symbol name from Memory Reserve | "" | Symbol name from Memory Variable block dropdown | -| offsetValue | Integer | 0 to (buffer_size - dataSize) | 0 | Byte offset from symbol start, validated against buffer size | -| dataSize | Integer | 1-112 | 4 | Number of bytes to read/write (1-112 bytes, register-aligned for >=4) | - -### Example Configurations - -**Read 4 bytes from beginning of buffer:** -\\\`\\\`\\\`javascript -// First create Memory Variable block -const memory_reserve = scripting.addModule("/pru_blocks/utils/memory_variable_block", {}, false); -const mem_reserve1 = memory_reserve.addInstance(); -mem_reserve1.$name = "Memory_Reserve_0"; -mem_reserve1.labelName = "rxBuffer"; -mem_reserve1.sizeInBytes = 128; -mem_reserve1.memoryLocation = "dmem"; // Local PRU memory - -// Configure Memory Access to read from it -mem_access1.$name = "Memory_Access_Read"; -mem_access1.operationMode = "read"; -mem_access1.symbolSelect = "rxBuffer"; -mem_access1.offsetValue = 0; -mem_access1.dataSize = 4; -\\\`\\\`\\\` - -**Write to shared memory buffer with offset:** -\\\`\\\`\\\`javascript -// First create Memory Variable block in shared memory -const memory_reserve = scripting.addModule("/pru_blocks/utils/memory_variable_block", {}, false); -const mem_reserve1 = memory_reserve.addInstance(); -mem_reserve1.$name = "Memory_Reserve_0"; -mem_reserve1.labelName = "sharedData"; -mem_reserve1.sizeInBytes = 256; -mem_reserve1.memoryLocation = "smem"; // Shared memory for PRU-ARM communication - -// Configure Memory Access to write to offset 0x10 -mem_access1.$name = "Memory_Access_Write"; -mem_access1.operationMode = "write"; -mem_access1.symbolSelect = "sharedData"; -mem_access1.offsetValue = 0x10; // Write to bytes 16-19 -mem_access1.dataSize = 4; -\\\`\\\`\\\` - -### Connecting to Other Blocks - -\\\`\\\`\\\`javascript -// For WRITE mode: connect data source to input1 -scripting.connect(load_constant1, "output1", mem_access1, "input1"); - -// For READ mode: connect output1 to downstream block -scripting.connect(mem_access1, "output1", process_block, "input1"); - -// Connect control flow -scripting.connect(prev_block, "next", mem_access1, "prev"); -\\\`\\\`\\\` - -### Important Notes - -1. **Write Mode Inputs**: When operationMode="write", connect data to input1. If offsetMode="register", also connect offset to input2. - -2. **Read Mode Outputs**: When operationMode="read", the loaded data is available on output1. - -3. **Symbol Addressing**: When using addressingMode="symbol", the symbol must be defined by a Memory Variable block in the same configuration. -`; -} function getLongDescription() { - return ` + return `NOTE: Before making any assumptions about this block's parameters, behavior, or configuration, always read the docs file at: docs_ai/utils/memory_access_block.md + ## Memory Access Block ### Purpose @@ -391,7 +310,6 @@ exports = { displayName: "Memory Access", defaultInstanceName: "Memory_Access_", longDescription: getLongDescription(), - getAIContext: getAIContext, uiView: "graph", templates: { "/pru_blocks/common/pru_syscfg.asm.xdt": null diff --git a/.metadata/sysconfig/.meta/pru_blocks/utils/memory_variable_block.syscfg.js b/.metadata/sysconfig/.meta/pru_blocks/utils/memory_variable_block.syscfg.js index 13c3721..eb810bd 100644 --- a/.metadata/sysconfig/.meta/pru_blocks/utils/memory_variable_block.syscfg.js +++ b/.metadata/sysconfig/.meta/pru_blocks/utils/memory_variable_block.syscfg.js @@ -45,85 +45,11 @@ function getUsectDirective(instance) { return `${labelName}\t.usect "${sectionName}", ${sizeInBytes}, 4`; } -function getAIContext() { - return getLongDescription() + ` -## How to Configure (For AI/Scripting) - -This section describes how to programmatically configure the Memory Variable block in a .syscfg file. - -### Adding a Memory Variable Instance - -\\\`\\\`\\\`javascript -const memory_variable = scripting.addModule("/pru_blocks/utils/memory_variable_block", {}, false); -const mem_variable1 = memory_variable.addInstance(); -\\\`\\\`\\\` - -### Configuration Parameters - -| Parameter | Type | Valid Values | Default | Description | -|-----------|------|--------------|---------|-------------| -| labelName | String | Valid C identifier | "buffer" | Symbol name for the reserved memory | -| sizeInBytes | Integer | 1-8192 | 64 | Number of bytes to reserve | -| memoryLocation | String | "dmem" or "smem" | "dmem" | Memory location (DMEM=local, SMEM=shared) | - -### Example Configurations - -**Local buffer in DMEM:** -\\\`\\\`\\\`javascript -mem_variable1.$name = "Memory_Variable_0"; -mem_variable1.labelName = "rxBuffer"; -mem_variable1.sizeInBytes = 128; -mem_variable1.memoryLocation = "dmem"; -\\\`\\\`\\\` - -**Shared buffer in SMEM:** -\\\`\\\`\\\`javascript -mem_variable1.$name = "Shared_Buffer"; -mem_variable1.labelName = "ipcBuffer"; -mem_variable1.sizeInBytes = 512; -mem_variable1.memoryLocation = "smem"; -\\\`\\\`\\\` - -### Using with Memory Access Block - -\\\`\\\`\\\`javascript -// Create Memory Reserve in DMEM -const memory_variable = scripting.addModule("/pru_blocks/utils/memory_variable_block", {}, false); -const mem_variable1 = memory_variable.addInstance(); -mem_variable1.$name = "Memory_Variable_0"; -mem_variable1.labelName = "my_buffer"; -mem_variable1.sizeInBytes = 64; -mem_variable1.memoryLocation = "dmem"; - -// Create Memory Access that references the symbol -const memory_load_block = scripting.addModule("/pru_blocks/data_handling/memory_load_block", {}, false); -const mem_access1 = memory_load_block.addInstance(); -mem_access1.$name = "Memory_Access_0"; -mem_access1.operationMode = "write"; -mem_access1.addressingMode = "symbol"; -mem_access1.symbolSelect = "my_buffer"; // References the labelName above -mem_access1.dataSize = 4; -\\\`\\\`\\\` - -### Important Notes - -1. **Label Name Rules**: Must start with a letter or underscore, and contain only letters, numbers, and underscores. - -2. **No Runtime Code**: This block only generates a .usect directive - no executable instructions. - -3. **Alignment**: Memory is always 4-byte (word) aligned for optimal PRU access. - -4. **Uninitialized**: Reserved memory has undefined contents at startup. Use Lookup Table block for initialized data. - -5. **Memory Location**: - - **DMEM (Local)**: 8 KB per PRU, fastest access, private to each PRU - - **SMEM (Shared)**: 64 KB total, accessible by all PRUs and ARM cores, use for inter-core communication -`; -} function getLongDescription() { - return ` + return `NOTE: Before making any assumptions about this block's parameters, behavior, or configuration, always read the docs file at: docs_ai/utils/memory_variable_block.md + ## Memory Variable Block ### Purpose @@ -248,7 +174,6 @@ exports = { displayName: "Memory Variable", defaultInstanceName: "Memory_Variable_", longDescription: getLongDescription(), - getAIContext: getAIContext, uiView: "graph", templates: { "/pru_blocks/common/pru_syscfg.asm.xdt": null diff --git a/AGENTS.md b/AGENTS.md index f357b26..6b50160 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -6,16 +6,22 @@ This file guides AI assistants when working with the PRU No-Code Tool inside TI ## Critical Rules -**Rule 1: MANDATORY — Always `listModules()` → `getAIContext()` → `addModuleInstances()`** +**Rule 1: MANDATORY — Always `listModules()` → Read docs `.md` files → `addModuleInstances()`** - Call `listModules()` to get exact full module paths (short names like `"uart_tx"` do NOT work) -- Call `getAIContext(modulePath)` on every block before adding it — **NO EXCEPTIONS**, even for familiar blocks -- **CRITICAL: Read the "How to Configure (For AI/Scripting)" section in the context — this is ESSENTIAL for proper functioning** -- Reason: `getAIContext()` reveals critical details you CANNOT guess: +- Read the docs `.md` file for every block before adding it — **NO EXCEPTIONS**, even for familiar blocks +- **ALSO READ THE DOCS FILE:** Pattern is `docs_ai//.md`. Key examples per category: + - Program Control: `docs_ai/program_control/loop_block.md`, `conditional_block.md`, `flow_control_block.md` + - Data Handling: `docs_ai/data_handling/load_constant_block.md`, `arithmetic_block.md` + - PRU I/O: `docs_ai/pru_io_blocks/pru_gpi_block.md`, `pru_spi_read.md` + - Utilities: `docs_ai/utils/delay_block.md`, `memory_variable_block.md` + - Always read the "How to Configure (For AI/Scripting)" section. +- **CRITICAL: Read the "How to Configure (For AI/Scripting)" section in the docs file** — this is ESSENTIAL +- Reason: The `.md` docs reveal critical details you CANNOT guess: - Parameter encodings (e.g., `oversampleSize = 7` means 8x oversampling, not 8) - Baud rate calculation formulas and timing constraints - Correct parameter types (int vs string) - Valid value ranges and special encodings -- If you skip this step, acknowledge your mistake immediately and re-read the full context before proceeding +- If you skip reading the docs, acknowledge your mistake immediately and read the full `.md` file before proceeding **Rule 2: Semantic naming prevents connection errors** - Rename blocks immediately after creation to reflect PURPOSE, not just type @@ -33,7 +39,7 @@ This file guides AI assistants when working with the PRU No-Code Tool inside TI **Rule 4: Always build after completing block setup** - After adding, configuring, and connecting blocks, trigger a build to check for errors -- Fix errors before reporting the setup as complete +- Fix errors before reporting and build again to check for any other errors **Rule 5: Always `getModuleInstances()` after renaming a block** - When you set `$name` on an instance, the `moduleInstanceId` auto-updates @@ -43,7 +49,7 @@ This file guides AI assistants when working with the PRU No-Code Tool inside TI **Rule 6: No AI tool for connections — edit .syscfg directly** - Add `scripting.connect(instanceA, "portOnA", instanceB, "portOnB")` calls in the `.syscfg` file under "Connections between modules" - Port types: `"output1"`/`"input1"` (data), `"next"`/`"prev"` (control flow) -- If `getAIContext()` returns nothing, verify the path with `listModules()` first +- If the docs file (`docs_ai//.md`) is missing, verify the block path with `listModules()` first --- @@ -52,7 +58,7 @@ This file guides AI assistants when working with the PRU No-Code Tool inside TI | Tool | Purpose | |------|---------| | `listModules()` | Get exact full paths for all available blocks | -| `getAIContext(modulePath)` | Read block documentation, parameters, encodings, and usage notes | +| `readDocs(filePath)` | Read `.md` docs file at `docs_ai//.md` for parameters, encodings, usage notes | | `addModuleInstances(modulePath, configs)` | Add block instances with configuration | | `getModuleInstances(modulePath)` | Get current instances including up-to-date IDs (call after rename) | | `removeModuleInstances(modulePath, instanceIds)` | Remove block instances | @@ -76,32 +82,6 @@ This file guides AI assistants when working with the PRU No-Code Tool inside TI - Verify the SOURCE of each input (is it the right block?) - Verify the PURPOSE of each value (does it make logical sense?) -**Example (UART TX with 8-bit data + 8-bit CRC in single frame):** - -``` -Data Flow (outline first): - Load_Constant (data=0xAA) ─┬─→ CRC block (data input) - ├─→ Bitwise_OR (lower byte) - └─→ [WRONG CONNECTION - don't do this] - - Load_Constant (crc_init=0) ─→ CRC block (init input) - - Load_Constant (shift_amt=8) ─→ Bitwise_LSL (shift amount) ✓ - - CRC block (output) ─→ Bitwise_LSL (data to shift) - - Bitwise_LSL (output) ─→ Bitwise_OR (upper byte) - - Load_Constant (data=0xAA) ─→ Bitwise_OR (lower byte) - - Bitwise_OR (output) ─→ UART_TX (16-bit frame) -``` - -**Key insight from planning:** -- Need **3 Load Constants**, not 2 (data, crc_init, shift_amount) -- Shift amount is a **constant (8)**, NOT the data value (0xAA) -- Each constant has a **distinct purpose** — name it accordingly - --- ### Step 1: Add and Name Blocks (Semantic Naming) @@ -110,11 +90,7 @@ Data Flow (outline first): 2. `addModuleInstances(modulePath, {})` → add blocks 3. **Immediately rename each block to reflect its PURPOSE:** - `Load_Constant_0` → `Data_Byte` (or `Data_0xAA`) - - `Load_Constant_1` → `CRC_Init_Zero` (or `CRC_Init`) - - `Load_Constant_2` → `Shift_Amount_8` (or `Shift_8`) - `CRC_0` → `CRC_8bit` (clarifies CRC type) - - `Bitwise_0` → `CRC_ShiftLeft_8` (clarifies operation) - - `Bitwise_1` → `Combine_Data_CRC` (clarifies purpose) **Why:** When connecting later, semantic names make it obvious which constant goes where. @@ -122,83 +98,16 @@ Data Flow (outline first): ### Step 2: Configure and Validate Inputs -1. `getAIContext(modulePath)` for each block → read parameters, types, valid values +1. Read the docs `.md` file (`docs_ai//.md`) for the block → read parameters, types, valid values 2. `changeConfiguration()` → set values 3. **For each configurable, write down:** - What it does - Why this value (reference the pre-planning) - Expected behavior - - Example: - ``` - Load_Constant (Data_Byte): - - constant1 = 170 (0xAA) - - Purpose: 8-bit data payload to be CRC'd and transmitted - - Load_Constant (CRC_Init): - - constant1 = 0 - - Purpose: CRC starts fresh (not chained from previous CRC) - - Load_Constant (Shift_Amount): - - constant1 = 8 - - Purpose: Shift CRC left 8 bits to place in upper byte - - Math: 16-bit frame = [CRC:8 bits][Data:8 bits] - - Bitwise (CRC_ShiftLeft_8): - - opCode = LSL (left shift) - - input1 = CRC_8bit.output1 (the CRC to shift) - - input2 = Shift_Amount_8.output1 (shift by 8) - - output = 16-bit result (CRC now in upper byte) - ``` - ---- - -### Step 3: Pre-Connection Validation Checklist - -**Before editing .syscfg to add `scripting.connect()` calls:** - -For each block input, answer these questions: - -``` -BLOCK: Bitwise_0 (CRC_ShiftLeft_8) -□ input1: Should receive CRC output? - Source: CRC_0.output1 ✓ - Semantically: "Shift the CRC result left" ✓ - Type: 8 bits → 16 bits after LSL ✓ - -□ input2: Should receive shift amount? - Source: Load_Constant_2 (Shift_Amount_8) ✓ - NOT: Load_Constant_0 (Data_Byte) ✗ - Semantically: "Shift by 8 bits" ✓ - Math check: CRC << 8 makes sense for [CRC:8][Data:8] frame ✓ - -BLOCK: Bitwise_1 (Combine_Data_CRC) -□ input1: Should receive shifted CRC (upper byte)? - Source: Bitwise_0.output1 ✓ - NOT: Load_Constant_0 (Data_Byte) ✗ - Semantically: "Upper byte is shifted CRC" ✓ - -□ input2: Should receive original data (lower byte)? - Source: Load_Constant_0 (Data_Byte) ✓ - NOT: something else ✓ - Semantically: "Lower byte is original data" ✓ - -BLOCK: UART_TX_0 -□ input1: Should receive combined 16-bit frame? - Source: Bitwise_1.output1 ✓ - Size: 16 bits (matches dataBits=16 config) ✓ - Content: [CRC:8][Data:8] ✓ -``` - -**Catch errors BEFORE building by asking:** -- Is the SOURCE block correct? -- Is the SOURCE port correct? -- Does the semantic PURPOSE match the connection? -- Does the data SIZE/TYPE match? --- -### Step 4: Connect Blocks and Build +### Step 3: Connect Blocks and Build 1. Edit `.syscfg` → add `scripting.connect()` calls (use semantic names from Step 1) 2. [If renamed] `getModuleInstances()` → retrieve updated IDs (if needed) @@ -238,22 +147,6 @@ CONNECT & BUILD: --- -## Connection Example - -```js -// Data connections -scripting.connect(load_constant_1, "output1", memory_access_1, "input1"); -scripting.connect(memory_access_1, "output1", uart_tx1, "input1"); - -// Control flow (execution order) -scripting.connect(load_constant_1, "next", memory_access_1, "prev"); -scripting.connect(memory_access_1, "next", uart_tx1, "prev"); -``` - -Key: Blocks can have both data and control connections. Port names matter; order of pairs doesn't. - ---- - ## Architecture Facts - Generates **PRU assembly code** (not C) @@ -320,18 +213,6 @@ CRC_0 (output = 8 bits) → Bitwise_LSL (input1) → OR (input1) → UART_TX (ex 2. **Verify compatibility:** Check if next block's input matches the output size 3. **Test the chain:** Mentally execute: CRC (8b) → LSL (16b) → OR (16b) → UART (16b) ✓ -### Mistake 4: Forgetting to Update Block Names After Creation - -**What happens:** -- You create `Load_Constant_0`, `Load_Constant_1`, `Load_Constant_2` -- Later, when connecting, you're not sure which is which -- You accidentally connect the wrong one - -**How to avoid:** -1. **Rename immediately after creation** (Step 1 of Design Build Pattern) -2. **Use clear semantic names** that describe PURPOSE, not just type -3. **Verify names match connections** when editing .syscfg - --- ## Quick Reference diff --git a/README.md b/README.md index 98a2634..dd538dc 100644 --- a/README.md +++ b/README.md @@ -304,6 +304,10 @@ done: | sysconfig_generated_start | Entry point for ungrouped blocks | | sysconfig_generated_end | Exit point for ungrouped blocks | | _start | Entry point for a Group block | +| _start | Entry point for any individual block — addressable by a [Flow Control block](docs/program-control/flow_control_block.md) to (re-)run that block | +| _end | Exit point for any ordinary block (position right after that block's own instruction) | + +If/Else (Conditional) blocks only expose `_start` — they have two forward addresses (`_TRUE`/`_FALSE`), not a single "end". Every one of these labels appears directly in a [Flow Control block](docs/program-control/flow_control_block.md)'s "Jump To" dropdown — no manual label-name entry required. --- diff --git a/docs/images/break_using_flow_control_0.png b/docs/images/break_using_flow_control_0.png new file mode 100644 index 0000000..71c8119 Binary files /dev/null and b/docs/images/break_using_flow_control_0.png differ diff --git a/docs/images/break_using_flow_control_1.png b/docs/images/break_using_flow_control_1.png new file mode 100644 index 0000000..984de3f Binary files /dev/null and b/docs/images/break_using_flow_control_1.png differ diff --git a/docs/images/continue_using_flow_control_loop.png b/docs/images/continue_using_flow_control_loop.png new file mode 100644 index 0000000..f582781 Binary files /dev/null and b/docs/images/continue_using_flow_control_loop.png differ diff --git a/docs/program-control/conditional_block.md b/docs/program-control/conditional_block.md index 177ed80..b95c51b 100644 --- a/docs/program-control/conditional_block.md +++ b/docs/program-control/conditional_block.md @@ -51,12 +51,12 @@ Implements conditional logic to control program flow based on comparing two inpu ### Generated Assembly ```assembly -QBGT TRUE_LABEL, input1_reg, input2_reg ; Branch if input1 > input2 (1 cycle) +QBGT If_Else_0_TRUE, input1_reg, input2_reg ; Branch if input1 > input2 (1 cycle) ; FALSE path blocks here -QBA END_LABEL ; Jump past true path -TRUE_LABEL: +; FALSE branch MUST end in a Flow Control block (see "Flow Control Requirement" below) +If_Else_0_TRUE: ; TRUE path blocks here -END_LABEL: +; TRUE branch MUST end in a Flow Control block ``` ### Technical Details @@ -64,6 +64,16 @@ END_LABEL: - **Performance**: 1 PRU cycle for the comparison and branch - **Comparison type**: All comparisons are **unsigned** — values treated as positive integers - Both `t_next` and `f_next` ports should be connected (warnings issued if not) +- Every block, including this one, has an addressable `_start` entry point that a [Flow Control block](flow_control_block.md) elsewhere in the design can jump to (e.g. to re-run this comparison) + +### Flow Control Requirement + +The FALSE path is placed immediately after the branch instruction, with the TRUE path at the branch target label. **Any connected branch (t_next or f_next) that has no explicit terminator falls through into the other branch — causing both to execute regardless of the condition.** SysConfig validation enforces this as an error: every connected branch must end in a [Flow Control block](flow_control_block.md). Leaving a branch entirely unconnected is fine; only connected-but-unterminated branches are rejected. + +**Where that Flow Control block should jump to depends on where the If/Else block lives:** + +- **Standalone If/Else** (not inside a Loop block): jump to Sysconfig Generated End, Halt, or any other block's `_start` target. +- **If/Else nested inside a Loop block**: jump to that Loop's own `_start` target so execution resumes the loop instead of exiting the whole program. Jumping to Sysconfig Generated End or Halt from inside a loop's branch ends the entire program early rather than just this iteration — only do that if that's genuinely the intent. To break out of the loop early, use Flow Control to jump to the next block (connected to loop next port) or sysconfig_generated_end. ### Common Use Cases @@ -71,5 +81,6 @@ END_LABEL: - Zero detection (`notEqualToInput2` with input2 = 0) - Range validation - State machine transitions +- Loop break (nested inside a Loop block, jump to next block via Flow Control) --- diff --git a/docs/program-control/flow_control_block.md b/docs/program-control/flow_control_block.md index f9fa02e..18b7a25 100644 --- a/docs/program-control/flow_control_block.md +++ b/docs/program-control/flow_control_block.md @@ -4,20 +4,21 @@ ### Purpose -Controls PRU program flow by either jumping to the end of SysConfig-generated code or halting the PRU immediately. This is a terminating block — it has no output port. +Controls PRU program flow by jumping to the end of SysConfig-generated code, halting the PRU immediately, or jumping to the entry (`_start`) or exit (`_end`) point of any other block in the design. This is a terminating block — it has no output port. ### Features -- Two modes: jump to generated end label, or halt the PRU +- Single dropdown listing every valid jump target in the current design - Single-cycle execution - Terminating block — no next connection - Distinct circular shape in the UI +- Target list is validated against the live design — renamed/removed blocks are flagged as errors, not silently broken ### Configuration | Parameter | Description | Options | |-----------|-------------|---------| -| Jump To | What to do when this block is reached | Sysconfig Generated End, Halt | +| Jump To | Where to jump when this block is reached | Sysconfig Generated End, Halt, or any block's `_start`/`_end` target in the current design | ### Options @@ -31,27 +32,44 @@ Controls PRU program flow by either jumping to the end of SysConfig-generated co - No cleanup or epilogue code runs - Use for emergency stops or when no further cleanup is needed +**Any block's `_start` target**: +- Every block in the design exposes an addressable `_start` entry point +- Select the target directly from the same dropdown — no separate free-text field +- If the referenced block is later renamed or deleted, SysConfig flags this block as invalid at validation time instead of silently generating a broken jump + +### `_start` vs `_end` + +- **`_start`**: jump here to (re-)run that block from its entry point. For a Loop block, jumping here for a finite loop re-arms LOOP (counter reloads), not a clean continue; only for infinite loops (startloop_N with QBA) does it act like a true continue. +- **`_end`**: for ordinary blocks, the position immediately after that block's own instruction and not exposed as an option to jump to using flow control. For Loop blocks, for breaking out of the loop we can have a flow control which can jump to the block which comes next to the loop block, connected to next port of the loop block +- If/Else blocks only expose `_start` — no `_end` is offered for them. + ### Generated Assembly ```assembly -; Sysconfig Generated End mode: +; Sysconfig Generated End: JMP sysconfig_generated_end ; Jump to end label (1 cycle) -; Halt mode: +; Halt: HALT ; Stop PRU execution (1 cycle) + +; Jump to a block's start (e.g. re-entering a Loop): +JMP Loop_0_start ; Jump to that block's entry point (1 cycle) + ``` ### Technical Details -- **Performance**: 1 PRU cycle +- **Performance**: 1 PRU cycle for any option - **Shape**: Circle (distinct from square data blocks) - **No output ports** — execution ends here - Multiple Flow Control blocks can exist in different paths of the same design +- The dropdown only lists real, currently-existing targets in the design — it is rebuilt live from every block's `$name`, so it always reflects the current design state ### Common Use Cases -- Exiting from a conditional branch early (e.g., error detected → jump to end) -- Ending the true or false path of an If/Else block +- Ending the true or false path of an If/Else block (see [If/Else block](conditional_block.md)) +- Re-entering a Loop block from inside a nested branch (jump to `_start`) +- Breaking out of a Loop early from inside its body (jump to the start of the next block connected after loop block) - Stopping the PRU after one-shot initialization completes - Emergency halt on fault conditions @@ -63,4 +81,19 @@ If/Else (error != 0) └── f_next → [continue normal flow] ``` +### Example: Continuing a Loop from a Nested If/Else + +``` +Loop_0 + └── If/Else (check exit condition) + ├── t_next → Flow Control (Jump To = "SPI_block_start") ; break out of the loop and jump outside to the start of the next block connected + └── f_next → Flow Control (Jump To = "Loop_0_start") ; continue looping +``` + --- + +### Disconnected Subgraphs +Every disconnected chunk of blocks (subgraphs with no incoming `prev` connection) must terminate in a Flow Control block. Without this, execution from one chunk falls through into the next chunk, causing unexpected behavior. The tool validates this and reports an error (`Disconnected chunk 'X' missing Flow Control termination`) if any disconnected subgraph doesn't end with Flow Control. + +### Unreachable Chunk Warnings +After simulation, any emitted block label (`_start`, `_end`, `startloop_*`, `endloop_*`) that was never executed produces a visible warning (`Unreachable chunk: label 'X'...`). This helps identify dead or disconnected code that the simulation never reaches. diff --git a/docs/program-control/loop_block.md b/docs/program-control/loop_block.md index 4bf84c3..023dd40 100644 --- a/docs/program-control/loop_block.md +++ b/docs/program-control/loop_block.md @@ -30,6 +30,32 @@ Repeats a sequence of blocks a fixed number of times or infinitely. This is a co 3. **Optionally** mark blocks as Pre-Initialization to run them once before the loop 4. On each iteration, all non-pre-init blocks execute in connection order +### Continue and Break implementation using Flow Control Blocks + +#### Continue +We can use Flow control to select the start label of the loop block (e.g. `loop_0_start`). For a finite loop, this reloads the counter (restarts the loop with the original count), not a true continue. Only for an infinite loop does jumping back to `_start` behave like a clean continue, as shown below with the `tamagawa_single_channel` example. + +
+continue +
Implement continue in infinite loop
+
+ +#### Break +We can use Flow control to select the start label of the block connected outside the loop block and then jump to its start label using the flow control, check out the below image in which we implement break when a condition is satisfied + +
+continue +
SPI block is connected next to loop block
+
+ +
+continue +
In the true branch of if/else SPI read block's start label is selected to jump to using the flow control
+
+ + + + ### Pre-Initialization Blocks Pre-init blocks are physically inside the loop container but their generated code is placed **before** the loop instruction. This is useful for: @@ -84,13 +110,14 @@ QBA startloop_label ; Unconditional jump back | Scenario | Overhead | |----------|---------| -| Fixed loop setup | 2–3 cycles (counter load + LOOP instruction) | -| Per iteration (fixed) | 2 cycles (hardware decrement + branch) | +| Fixed loop setup (for finite loop) | 2 cycle (counter load + LOOP instruction) | | Per iteration (infinite) | 1 cycle (unconditional jump) | -**Total cycles** = setup_overhead + (loop_count × body_cycles) +**Total cycles** +for finite loop : 2 + (loop_body)*iterations +for infinite loop : (1 + loop_body) per iteration -Example: 100 iterations, body = 11 cycles → 3 + (100 × 11) = 1103 cycles = 5.515 µs at 200 MHz +Example: 100 iterations, body = 11 cycles → 2 + (100 × 11) = 1102 cycles = 5.510 µs at 200 MHz ### Loop Counter Register Sizing @@ -113,5 +140,6 @@ Example: 100 iterations, body = 11 cycles → 3 + (100 × 11) = 1103 cycles = 5. - Infinite loops **never exit** — the `next` port is hidden and no code after the loop is reachable - Loop counter occupies a register during loop execution - Pre-init blocks are still visually inside the container but their instructions are hoisted out +- A **Flow Control** block elsewhere can jump to this loop's label (`startloop_label` for infinite). Note: for finite loops, jumping to `_start` re-arms `LOOP` (counter reloads), not a true continue; only infinite loops continue cleanly. --- diff --git a/docs_ai/application_specific/crc_block.md b/docs_ai/application_specific/crc_block.md new file mode 100644 index 0000000..b5c9e51 --- /dev/null +++ b/docs_ai/application_specific/crc_block.md @@ -0,0 +1,175 @@ +## CRC Block (Cyclic Redundancy Check) + +### Purpose +Calculates CRC checksums for error detection in data transmission and storage. CRC is a hash function that detects accidental changes to raw data. + +### How It Works +1. **Input 1 (init)**: Connect CRC initialization value (either 0 from Load Constant or output from previous CRC block) +2. **Input 2 (data)**: Connect the data byte to process +3. **Process**: Uses table lookup and XOR operations to efficiently compute CRC +4. **Output**: Provides updated CRC value for next block or final checksum + +### Configuration + +**CRC Type**: Choose checksum size +- **CRC8**: 8-bit checksum (1 byte, 0-255) +- **CRC16**: 16-bit checksum (2 bytes, 0-65535) +- **CRC32**: 32-bit checksum (4 bytes, full 32-bit range) + +**CRC Polynomial**: The generator polynomial in hexadecimal +- Defines the mathematical algorithm for CRC calculation +- Common polynomials: + - CRC8: 0x07 (x⁸ + x² + x + 1) + - CRC16: 0x8005 (x¹⁶ + x¹⁵ + x² + 1) + - CRC32: 0x04C11DB7 (Ethernet/ZIP polynomial) + +**CRC Initialization**: How to initialize the CRC accumulator +- **initialize_crc_result_with_zeros**: Start fresh calculation (connect LOAD_CONSTANT with value 0) +- **initialize_crc_result_from_crcblock**: Continue from previous CRC (chain CRC blocks) + +### Technical Details (Additional Information) + +**Generated Assembly** (CRC8 example): +- LDI32 TEMP_REG1, CRC_LUT_address ; Load LUT address +- XOR TEMP_REG2.b0, init, dataByte ; XOR init with data +- LBBO &result, TEMP_REG1, TEMP_REG2.b0, 1 ; Lookup (6 cycles) + + +**Generated Assembly** (CRC16 example): +- LDI32 TEMP_REG1, CRC_LUT_address ; Load LUT address +- LSR TEMP_REG2.b0, init, 8 ; Extract high byte +- XOR TEMP_REG2.b0, TEMP_REG2.b0, dataByte ; XOR with data +- LBBO &result, TEMP_REG1, TEMP_REG2.b0, 2 ; Lookup +- LSL TEMP_REG2, init, 8 ; Shift init left +- XOR result, TEMP_REG2.w0, result ; XOR with lookup (9 cycles) + +**Generated Assembly** (CRC32 example): +- LDI32 TEMP_REG1, CRC_LUT_address ; Load LUT address +- LSR TEMP_REG2.b0, init, 24 ; Extract high byte +- XOR TEMP_REG2.b0, TEMP_REG2.b0, dataByte ; XOR with data +- LBBO &result, TEMP_REG1, TEMP_REG2.b0, 4 ; Lookup +- LSL TEMP_REG2, init, 8 ; Shift init left +- XOR result, TEMP_REG2, result ; XOR with lookup (9 cycles) + +**Performance**: +- CRC8: 6 PRU cycles per byte +- CRC16: 9 PRU cycles per byte +- CRC32: 9 PRU cycles per byte + +**Lookup Table**: Automatically generated 256-entry table based on polynomial +- CRC8: 256 bytes (256 × 1 byte) +- CRC16: 512 bytes (256 × 2 bytes) +- CRC32: 1024 bytes (256 × 4 bytes) +- Table stored in PRU DMEM +- Pre-computed at configuration time + +### How CRC Works + +**Algorithm Overview**: +1. Initialize CRC register (typically to 0) +2. For each data byte: + - XOR with appropriate bits of current CRC + - Use result as index into lookup table + - Update CRC with table value +3. Final CRC value is the checksum + +**Why Use CRC?** +- Detects single-bit errors +- Detects burst errors +- Fast computation using lookup tables +- Widely used in networking (Ethernet), storage (ZIP), and embedded systems + +### Usage Notes +- Always initialize with zeros for first CRC calculation +- When processing multiple bytes, chain CRC blocks together +- Input data must be 1 byte (8 bits) +- The polynomial determines error detection capability +- Different standards use different polynomials - verify your protocol requirements +- LUT is shared between CRC blocks with same polynomial and type + +### Terminology +- **CRC**: Cyclic Redundancy Check - error-detecting code +- **Checksum**: Result of CRC calculation used to verify data integrity +- **Polynomial**: Mathematical basis for CRC algorithm (e.g., 0x07, 0x8005) +- **Generator polynomial**: Divisor used in CRC calculation +- **LUT**: Lookup Table - pre-computed CRC values for each possible byte +- **DMEM**: PRU Data Memory where lookup table is stored +- **Chaining**: Connecting CRC blocks to process multiple bytes sequentially +- **Error detection**: Ability to detect corrupted or modified data + +## How to Configure (For AI/Scripting) + +This section describes how to programmatically configure the CRC block in a .syscfg file. + +### Adding a CRC Instance + +```javascript +const crc_block = scripting.addModule("/pru_blocks/application_specific/crc_block", {}, false); +const crc1 = crc_block.addInstance(); +``` + +### Configuration Parameters + +| Parameter | Type | Valid Values | Default | Description | +|-----------|------|--------------|---------|-------------| +| opCode | String | "m_calculate_crc8", "m_calculate_crc16", "m_calculate_crc32" | "m_calculate_crc8" | CRC algorithm type | +| crcPolynomial | Hex | Depends on CRC type | 0x07 | CRC polynomial (generator) | +| output1Size | String | "1", "2", "4" | "1" | Output size in bytes | + +### Valid CRC Types and Polynomials + +| CRC Type | Default Polynomial | Common Polynomials | Description | +|----------|-------------------|-------------------|-------------| +| CRC8 | 0x07 | 0x07, 0x31, 0x9B | 8-bit CRC (1 byte output) | +| CRC16 | 0x8005 | 0x8005, 0x1021, 0x8408 | 16-bit CRC (2 byte output) | +| CRC32 | 0x04C11DB7 | 0x04C11DB7, 0xEDB88320 | 32-bit CRC (4 byte output) | + +### Example Configurations + +**Standard CRC8:** +```javascript +crc1.$name = "CRC8_Check"; +crc1.opCode = "m_calculate_crc8"; +crc1.crcPolynomial = 0x07; +crc1.output1Size = "1"; +``` + +**CRC16 for MODBUS:** +```javascript +crc1.$name = "CRC16_MODBUS"; +crc1.opCode = "m_calculate_crc16"; +crc1.crcPolynomial = 0x8005; +crc1.output1Size = "2"; +``` + +**CRC32 for Ethernet:** +```javascript +crc1.$name = "CRC32_Ethernet"; +crc1.opCode = "m_calculate_crc32"; +crc1.crcPolynomial = 0x04C11DB7; +crc1.output1Size = "4"; +``` + +### Connecting to Other Blocks + +```javascript +// Connect data input +scripting.connect(data_source, "output1", crc1, "input1"); + +// Connect CRC output to downstream block +scripting.connect(crc1, "output1", next_block, "input1"); + +// Connect control flow +scripting.connect(prev_block, "next", crc1, "prev"); +scripting.connect(crc1, "next", next_block, "prev"); +``` + +### Important Notes + +1. **Input Required**: input1 must be connected to provide data for CRC calculation. + +2. **Polynomial Selection**: Choose appropriate polynomial for your protocol/standard. + +3. **Output Size**: Must match CRC type (CRC8=1 byte, CRC16=2 bytes, CRC32=4 bytes). + +4. **Lookup Table**: Block generates optimized lookup table for fast CRC calculation. \ No newline at end of file diff --git a/docs_ai/data_handling/arithmetic_block.md b/docs_ai/data_handling/arithmetic_block.md new file mode 100644 index 0000000..e08ac69 --- /dev/null +++ b/docs_ai/data_handling/arithmetic_block.md @@ -0,0 +1,145 @@ +## Arithmetic Block + +### Purpose +Performs mathematical operations on two input values and outputs the result. Supports addition and subtraction with optional carry/borrow handling. + +### How It Works +1. **Connect Inputs**: Connect two data sources to input1 and input2 +2. **Select Operation**: Choose the arithmetic operation (ADD, ADC, SUB, SUC) +3. **Execute**: Generates the corresponding PRU arithmetic instruction +4. **Output**: Provides the calculation result to the next block + +### Available Operations + +**ADDITION** +- Standard add operation: result = input1 + input2 +- Ignores carry flag + +**ADDITION_WITH_CARRY** +- Includes carry from previous operation: result = input1 + input2 + carry +- Useful for multi-precision arithmetic (adding numbers larger than 32 bits) + +**SUBTRACT** +- Standard subtract: result = input1 - input2 +- Ignores borrow flag + +**SUBTRACT_WITH_BORROW** (note: displays as "SUBTRACT_WITH_BARROW" in UI) +- Includes borrow from previous operation: result = input1 - input2 - borrow +- Useful for multi-precision subtraction + +### Configuration +- **Math Operation**: Select ADD, ADC, SUB, or SUC +- **Output Size**: Choose result size +- **Maximum of Inputs**: Auto-size based on largest input (recommended) +- **One byte**: Force 8-bit result +- **Two bytes**: Force 16-bit result +- **Four bytes**: Force 32-bit result + +### Technical Details (Additional Information) +**Generated Assembly**: +- ADD result, input1, input2 ; Addition (1 cycle) +- ADC result, input1, input2 ; Addition with carry (1 cycle) +- SUB result, input1, input2 ; Subtraction (1 cycle) +- SUC result, input1, input2 ; Subtract with borrow (1 cycle) + +**Performance**: 1 PRU cycle for all operations + +### Carry/Borrow Flags +- PRU maintains a carry flag that is set/cleared by arithmetic operations +- ADC/SUC instructions use this flag for extended precision arithmetic +- Example: Adding two 64-bit numbers requires two ADC operations + +### Usage Notes +- Both inputs must be connected +- Output size should accommodate the expected result range +- Overflow is not detected - wraps around modulo 2^(output_size) + +### Terminology +- **Carry**: Overflow bit from addition, used in multi-word operations +- **Borrow**: Underflow bit from subtraction, used in multi-word operations +- **Multi-precision**: Arithmetic on numbers larger than register size + + +## How to Configure (For AI/Scripting) + +This section describes how to programmatically configure the Arithmetic block in a .syscfg file. + +### Adding an Arithmetic Instance + +\`\`\`javascript +const arithmetic_block = scripting.addModule("/pru_blocks/data_handling/arithmetic_block", {}, false); +const arith1 = arithmetic_block.addInstance(); +\`\`\` + +### Configuration Parameters + +| Parameter | Type | Valid Values | Default | Description | +|-----------|------|--------------|---------|-------------| +| opCode | String | "ADD", "ADC", "SUB", "SUC" | "ADC" | Math operation to perform | +| output1Size | String | "maxOfInputs", "1", "2", "4" | "maxOfInputs" | Output size in bytes | + +### Valid Values for opCode + +| Value | Display Name | Description | +|-------|--------------|-------------| +| "ADD" | Addition | result = input1 + input2 | +| "ADC" | Addition With Carry | result = input1 + input2 + carry | +| "SUB" | Subtract | result = input1 - input2 | +| "SUC" | Subtract With Borrow | result = input1 - input2 - borrow | + +### Valid Values for output1Size + +| Value | Display Name | Description | +|-------|--------------|-------------| +| "maxOfInputs" | Maximum of Inputs | Auto-size based on largest input | +| "1" | One byte | Force 8-bit result | +| "2" | two bytes | Force 16-bit result | +| "4" | four bytes | Force 32-bit result | + +### Example Configurations + +**Simple Addition:** +\`\`\`javascript +arith1.$name = "Add_Values"; +arith1.opCode = "ADD"; +arith1.output1Size = "maxOfInputs"; +\`\`\` + +**Subtraction with 32-bit output:** +\`\`\`javascript +arith1.$name = "Subtract_32bit"; +arith1.opCode = "SUB"; +arith1.output1Size = "4"; +\`\`\` + +**Addition with carry (for multi-precision):** +\`\`\`javascript +arith1.$name = "Add_With_Carry"; +arith1.opCode = "ADC"; +arith1.output1Size = "4"; +\`\`\` + +### Connecting to Other Blocks + +\`\`\`javascript +// Connect two data sources to inputs +scripting.connect(load_constant1, "output1", arith1, "input1"); +scripting.connect(load_constant2, "output1", arith1, "input2"); + +// Connect output to downstream block +scripting.connect(arith1, "output1", next_block, "input1"); + +// Connect control flow +scripting.connect(prev_block, "next", arith1, "prev"); +scripting.connect(arith1, "next", next_block, "prev"); +\`\`\` + +### Important Notes + +1. **Two Inputs Required**: Both input1 and input2 must be connected. + +2. **Carry/Borrow Flag**: ADC and SUC use the carry/borrow flag from previous arithmetic operations. + +3. **Single Cycle**: All arithmetic operations complete in 1 PRU cycle. + +4. **Overflow**: Results wrap around - no overflow detection. \ No newline at end of file diff --git a/docs_ai/data_handling/bitwise_block.md b/docs_ai/data_handling/bitwise_block.md new file mode 100644 index 0000000..23fbd7e --- /dev/null +++ b/docs_ai/data_handling/bitwise_block.md @@ -0,0 +1,176 @@ +## Bitwise Block + +### Purpose +Performs bitwise logical operations and bit shift operations on input values. Essential for bit manipulation, masking, and data formatting. + +### How It Works +1. **Connect Inputs**: Connect one or two data sources (depends on operation) +2. **Select Operation**: Choose the bitwise operation +3. **Execute**: Generates the corresponding PRU bitwise instruction +4. **Output**: Provides the result to the next block + +### Available Operations + +**AND** (2 inputs) +- Bitwise AND: result = input1 & input2 +- Used for masking bits, clearing specific bits +- Example: 0b1100 AND 0b1010 = 0b1000 + +**OR** (2 inputs) +- Bitwise OR: result = input1 | input2 +- Used for setting bits, combining flags +- Example: 0b1100 OR 0b1010 = 0b1110 + +**XOR** (2 inputs) +- Bitwise XOR (exclusive OR): result = input1 ^ input2 +- Used for toggling bits, comparison +- Example: 0b1100 XOR 0b1010 = 0b0110 + +**NOT** (1 input) +- Bitwise NOT (complement): result = ~input1 +- Inverts all bits +- Example: NOT 0b1100 = 0b0011 (in 4-bit) + +**LSL** (2 inputs) +- Logical Shift Left: result = input1 << input2 +- Shifts bits left, fills with zeros +- Equivalent to multiplying by 2^input2 +- Example: 0b0011 LSL 2 = 0b1100 + +**LSR** (2 inputs) +- Logical Shift Right: result = input1 >> input2 +- Shifts bits right, fills with zeros +- Equivalent to dividing by 2^input2 (unsigned) +- Example: 0b1100 LSR 2 = 0b0011 + +### Configuration +- **Bitwise Operation**: Select AND, OR, XOR, NOT, LSL, or LSR +- Number of inputs adjusts automatically based on operation + +### Technical Details (Additional Information) +**Generated Assembly**: +- AND result, input1, input2 ; Bitwise AND (1 cycle) +- OR result, input1, input2 ; Bitwise OR (1 cycle) +- XOR result, input1, input2 ; Bitwise XOR (1 cycle) +- NOT result, input1 ; Bitwise NOT (1 cycle) +- LSL result, input1, input2 ; Left shift (1 cycle) +- LSR result, input1, input2 ; Right shift (1 cycle) + +**Performance**: 1 PRU cycle for all operations + +### Common Use Cases +- **Masking**: Use AND with bitmask to extract specific bits +- **Setting flags**: Use OR to set specific bits to 1 +- **Toggling**: Use XOR to flip specific bits +- **Packing data**: Use shifts and OR to combine multiple values +- **Extracting fields**: Use shifts and AND to extract bit fields + +### Terminology +- **Bitwise**: Operations that work on individual bits +- **Mask**: Bit pattern used to select/clear specific bits +- **Shift**: Moving bits left or right within a value +- **Logical shift**: Shift that fills with zeros (vs arithmetic shift) + + +## How to Configure (For AI/Scripting) + +This section describes how to programmatically configure the Bitwise block in a .syscfg file. + +### Adding a Bitwise Instance + +\`\`\`javascript +const bitwise_block = scripting.addModule("/pru_blocks/data_handling/bitwise_block", {}, false); +const bitwise1 = bitwise_block.addInstance(); +\`\`\` + +### Configuration Parameters + +| Parameter | Type | Valid Values | Default | Description | +|-----------|------|--------------|---------|-------------| +| opCode | String | "AND", "OR", "XOR", "NOT", "LSL", "LSR" | "AND" | Bitwise operation to perform | +| output1Size | String | "maxOfInputs", "1", "2", "4" | "maxOfInputs" | Output size in bytes | + +### Valid Values for opCode + +| Value | Inputs | Description | +|-------|--------|-------------| +| "AND" | 2 | Bitwise AND: result = input1 & input2 | +| "OR" | 2 | Bitwise OR: result = input1 | input2 | +| "XOR" | 2 | Bitwise XOR: result = input1 ^ input2 | +| "NOT" | 1 | Bitwise NOT: result = ~input1 | +| "LSL" | 2 | Logical Shift Left: result = input1 << input2 | +| "LSR" | 2 | Logical Shift Right: result = input1 >> input2 | + +### Valid Values for output1Size + +| Value | Display Name | Description | +|-------|--------------|-------------| +| "maxOfInputs" | Maximum of Inputs | Auto-size based on largest input | +| "1" | One byte | Force 8-bit result | +| "2" | two bytes | Force 16-bit result | +| "4" | four bytes | Force 32-bit result | + +### Example Configurations + +**Bitwise AND (masking):** +\`\`\`javascript +bitwise1.$name = "Mask_Bits"; +bitwise1.opCode = "AND"; +bitwise1.output1Size = "maxOfInputs"; +\`\`\` + +**Bitwise OR (setting flags):** +\`\`\`javascript +bitwise1.$name = "Set_Flags"; +bitwise1.opCode = "OR"; +bitwise1.output1Size = "4"; +\`\`\` + +**Bitwise NOT (invert):** +\`\`\`javascript +bitwise1.$name = "Invert_Bits"; +bitwise1.opCode = "NOT"; +bitwise1.output1Size = "maxOfInputs"; +\`\`\` + +**Left Shift:** +\`\`\`javascript +bitwise1.$name = "Shift_Left"; +bitwise1.opCode = "LSL"; +bitwise1.output1Size = "4"; +\`\`\` + +**Right Shift:** +\`\`\`javascript +bitwise1.$name = "Shift_Right"; +bitwise1.opCode = "LSR"; +bitwise1.output1Size = "maxOfInputs"; +\`\`\` + +### Connecting to Other Blocks + +\`\`\`javascript +// For two-input operations (AND, OR, XOR, LSL, LSR) +scripting.connect(data_source, "output1", bitwise1, "input1"); +scripting.connect(mask_or_shift_amount, "output1", bitwise1, "input2"); + +// For single-input operation (NOT) +scripting.connect(data_source, "output1", bitwise1, "input1"); + +// Connect output to downstream block +scripting.connect(bitwise1, "output1", next_block, "input1"); + +// Connect control flow +scripting.connect(prev_block, "next", bitwise1, "prev"); +scripting.connect(bitwise1, "next", next_block, "prev"); +\`\`\` + +### Important Notes + +1. **Input Count**: NOT requires 1 input; all other operations require 2 inputs. + +2. **Single Cycle**: All bitwise operations complete in 1 PRU cycle. + +3. **Shift Amount**: For LSL/LSR, input2 specifies the number of bit positions to shift. + +4. **Logical Shift**: LSL and LSR fill vacated bits with zeros (no sign extension). \ No newline at end of file diff --git a/docs_ai/data_handling/load_constant_block.md b/docs_ai/data_handling/load_constant_block.md new file mode 100644 index 0000000..80c7db9 --- /dev/null +++ b/docs_ai/data_handling/load_constant_block.md @@ -0,0 +1,118 @@ +## Load Constant Block + +### Purpose +Loads an immediate constant value into a register. This is typically the starting block in a data flow, providing initial values or configuration parameters. + +### How It Works +1. **Enter Value**: Specify a constant value (0 to 0xFFFFFFFF) +2. **Auto-sizing**: Block automatically selects the appropriate instruction based on value size +3. **Output**: Provides the constant value to the next block + +### Configuration +- **Constant Value**: Enter any value from 0 to 4,294,967,295 (0xFFFFFFFF) + - Can be entered in decimal or hexadecimal format + - Block automatically determines optimal instruction + +### Technical Details (Additional Information) +**Generated Assembly** (auto-selected based on value size): +; For values 0-255 (8-bit): +LDI result, value ; 1 cycle + +; For values 256-65535 (16-bit): +LDI result, value ; 1 cycle + +; For values > 65535 (32-bit): +LDI32 result, value ; 1 cycle (uses two instruction slots) + +**Performance**: 1 PRU cycle + +### Usage Notes +- No input connections - this is a source block +- Output can be connected to any block that accepts data input +- Value is loaded at the time this block executes in the flow +- Commonly used for: + - Table indices + - Counter initialization + - Configuration values + - Bit masks + +### Terminology +- **LDI**: Load Immediate - instruction to load a constant into a register +- **LDI32**: Load 32-bit Immediate - instruction for full 32-bit constants +- **Immediate value**: Constant value embedded directly in the instruction + +--- + + +## How to Configure (For AI/Scripting) + +This section describes how to programmatically configure the Load Constant block in a .syscfg file. + +### Adding a Load Constant Instance + +\`\`\`javascript +const load_constant_block = scripting.addModule("/pru_blocks/data_handling/load_constant_block", {}, false); +const ldi1 = load_constant_block.addInstance(); +\`\`\` + +### Configuration Parameters + +| Parameter | Type | Valid Values | Default | Description | +|-----------|------|--------------|---------|-------------| +| constant1 | Integer | 0 to 0xFFFFFFFF | 0 | Constant value to load | + +### Example Configurations + +**Load small value (8-bit, uses LDI):** +\`\`\`javascript +ldi1.$name = "Load_Small"; +ldi1.constant1 = 0x55; // 85 decimal +\`\`\` + +**Load medium value (16-bit, uses LDI):** +\`\`\`javascript +ldi1.$name = "Load_Medium"; +ldi1.constant1 = 0x1234; // 4660 decimal +\`\`\` + +**Load large value (32-bit, uses LDI32):** +\`\`\`javascript +ldi1.$name = "Load_Large"; +ldi1.constant1 = 0xDEADBEEF; // 3735928559 decimal +\`\`\` + +**Load bit mask:** +\`\`\`javascript +ldi1.$name = "Bit_Mask"; +ldi1.constant1 = 0xFF00FF00; // Alternating byte mask +\`\`\` + +**Load zero:** +\`\`\`javascript +ldi1.$name = "Zero_Value"; +ldi1.constant1 = 0; +\`\`\` + +### Connecting to Other Blocks + +\`\`\`javascript +// Connect output to downstream block (e.g., arithmetic, UART TX, SPI) +scripting.connect(ldi1, "output1", arithmetic_block, "input1"); + +// Connect control flow +scripting.connect(prev_block, "next", ldi1, "prev"); +scripting.connect(ldi1, "next", next_block, "prev"); +\`\`\` + +### Important Notes + +1. **Source Block**: Load Constant has no input - it's a data source. + +2. **Auto-sizing**: The block automatically selects LDI (1 cycle) for values ≤ 0xFFFF and LDI32 (2 cycles) for larger values. + +3. **Output Size**: Output register size is automatically determined: +- 1 byte for values 0-255 +- 2 bytes for values 256-65535 +- 4 bytes for values > 65535 + +4. **Hexadecimal**: Values can be specified in hex (0x prefix) or decimal. \ No newline at end of file diff --git a/docs_ai/program_control/conditional_block.md b/docs_ai/program_control/conditional_block.md new file mode 100644 index 0000000..f062d94 --- /dev/null +++ b/docs_ai/program_control/conditional_block.md @@ -0,0 +1,199 @@ +## If/Else Block (Conditional Branching) + +### Purpose +Implements conditional logic (IF/ELSE statements) to control program flow based on comparing two input values. Directs execution to different paths depending on whether the condition is true or false. + +### How It Works +1. **Input 1**: First value to compare +2. **Input 2**: Second value to compare +3. **Condition**: Select comparison operation (>, <, ==, !=, >=, <=) +4. **Branching**: +- If condition is TRUE → executes blocks connected to **t_next** port +- If condition is FALSE → executes blocks connected to **f_next** port + +### Configuration + +**Condition To Check**: Select the comparison operation +- **Greater Than Input2**: Input1 > Input2 +- **Less Than Input2**: Input1 < Input2 +- **Equal To Input2**: Input1 == Input2 +- **Not Equal To Input2**: Input1 != Input2 +- **Greater Than Or Equal To Input2**: Input1 >= Input2 +- **Less Than Or Equal To Input2**: Input1 <= Input2 + +### Technical Details (Additional Information) + +**Generated Assembly**: +- ; Example: Greater Than Input2 (QBGT) +- FalseBranchHead_start: +- QBGT If_Else_0_TRUE, input1_reg, input2_reg ; Branch if input1 > input2 (1 cycle) +- ; FALSE path code here +- ; FALSE branch MUST end in a Flow Control block (e.g. JMP sysconfig_generated_end) +- If_Else_0_TRUE: +- TrueBranchHead_start: +- ; TRUE path code here +- ; TRUE branch MUST end in a Flow Control block + +**PRU Branch Instructions**: +- **QBGT**: Quick Branch if Greater Than (unsigned comparison) +- **QBLT**: Quick Branch if Less Than (unsigned comparison) +- **QBEQ**: Quick Branch if Equal +- **QBNE**: Quick Branch if Not Equal +- **QBGE**: Quick Branch if Greater than or Equal +- **QBLE**: Quick Branch if Less than or Equal + +**Performance**: 1 PRU cycle for the comparison and branch decision + +**Comparison Type**: All comparisons are **unsigned** integer comparisons +- Treats values as unsigned (0 to 255 for bytes, 0 to 65535 for shorts, etc.) +- Negative numbers are not supported in standard mode + +### Connection Ports + +**Input Ports**: +- **input1**: First comparison value +- **input2**: Second comparison value + +**Output Ports**: +- **t_next** (true next): Connect blocks to execute when condition is TRUE +- **f_next** (false next): Connect blocks to execute when condition is FALSE + +### Usage Notes +- Both input ports must be connected for conditional operation +- Both t_next and f_next ports should be connected to avoid warnings +- Comparisons are unsigned - values treated as positive integers +- The conditional check happens instantly (1 cycle) +- Code on both branches is generated, only one path executes at runtime +- This block does not produce an output value - it only controls flow +- **Any connected branch (T or F) MUST terminate in a Flow Control block**: The FALSE path falls through to the TRUE path in the generated assembly unless explicitly stopped, and vice versa. SysConfig validation now enforces this as an error — connect a Flow Control block at the end of every connected branch. Leaving a branch entirely unconnected is fine; only connected-but-unterminated branches are rejected. +- **What that Flow Control block should jump to depends on where the If/Else block lives**: + - **Standalone If/Else** (not inside a Loop block): jump to Sysconfig Generated End, Halt, or any other block's `_start` target. + - **If/Else nested inside a Loop block**: jump to that Loop's `_start` target so execution resumes the loop instead of exiting the whole program. Jumping to Sysconfig Generated End or Halt from inside a loop's branch ends the entire program early rather than just this iteration — only intentional if that's really the goal. To break out of the loop early, jump to the next connected block or sysconfig_generated_end via Flow Control. +- Every block, including this one and every block on either branch, has an addressable `_start` entry point that a Flow Control block elsewhere in the design can jump to (e.g. to re-run this comparison, or to re-enter a Loop block from inside a branch). + +### Terminology +- **Conditional branching**: Changing program flow based on a condition +- **IF/ELSE**: Fundamental programming construct for decisions +- **Branch instruction**: Assembly instruction that jumps to different code location +- **Quick Branch (QB)**: PRU's fast comparison and branch instructions +- **Unsigned comparison**: Treating all values as positive (0 to max) +- **Label**: Named location in assembly code for branching target +- **Control flow**: Order in which instructions execute +- **t_next/f_next**: True next and False next - execution paths after condition + +--- + +## How to Configure (For AI/Scripting) + +This section describes how to programmatically configure the If/Else (Conditional) block in a .syscfg file. + +### Adding an If/Else Instance + +\`\`\`javascript +const conditional_block = scripting.addModule("/pru_blocks/program_control/conditional_block", {}, false); +const if_else1 = conditional_block.addInstance(); +\`\`\` + +### Configuration Parameters + +| Parameter | Type | Valid Values | Default | Description | +|-----------|------|--------------|---------|-------------| +| conditionToCheck | String | See table below | "greaterThanInput2" | Comparison operation | + +### Valid Values for conditionToCheck + +| Value | Display Name | PRU Instruction | Description | +|-------|--------------|-----------------|-------------| +| "greaterThanInput2" | Greater Than Input2 | QBGT | input1 > input2 | +| "lessThanInput2" | Less Than Input2 | QBLT | input1 < input2 | +| "equalToInput2" | Equal To Input2 | QBEQ | input1 == input2 | +| "notEqualToInput2" | Not Equal To Input2 | QBNE | input1 != input2 | +| "greaterThanEqualtoInput2" | Greater Than Or Equal To Input2 | QBGE | input1 >= input2 | +| "lessThanEqualtoInput2" | Less Than Or Equal To Input2 | QBLE | input1 <= input2 | + +### Example Configurations + +**Check if value is greater than threshold:** +\`\`\`javascript +if_else1.$name = "Check_Threshold"; +if_else1.conditionToCheck = "greaterThanInput2"; +\`\`\` + +**Check for equality:** +\`\`\`javascript +if_else1.$name = "Check_Equal"; +if_else1.conditionToCheck = "equalToInput2"; +\`\`\` + +**Check if not zero:** +\`\`\`javascript +if_else1.$name = "Check_Not_Zero"; +if_else1.conditionToCheck = "notEqualToInput2"; +// Connect input1 to value, input2 to Load_Constant with value 0 +\`\`\` + +### Connecting to Other Blocks + +\`\`\`javascript +// Connect comparison inputs +scripting.connect(value_block, "output1", if_else1, "input1"); +scripting.connect(threshold_block, "output1", if_else1, "input2"); + +// Connect true path (executes when condition is TRUE) +scripting.connect(if_else1, "T", true_path_block, "prev"); + +// Connect false path (executes when condition is FALSE) +scripting.connect(if_else1, "F", false_path_block, "prev"); + +// Connect control flow input +scripting.connect(prev_block, "next", if_else1, "prev"); + +// REQUIRED: both true_path_block's and false_path_block's chains must each +// end in a Flow Control block, or validation fails. Example (standalone +// If/Else, NOT inside a Loop block): +const flow_control_block = scripting.addModule("/pru_blocks/program_control/flow_control_block", {}, false); +const flow_true = flow_control_block.addInstance(); +flow_true.$name = "Flow_Control_True_End"; +flow_true.jumpTarget = "JMP"; // or "HALT", or any real "_start" target to jump elsewhere +scripting.connect(true_path_block, "next", flow_true, "prev"); + +const flow_false = flow_control_block.addInstance(); +flow_false.$name = "Flow_Control_False_End"; +flow_false.jumpTarget = "JMP"; +scripting.connect(false_path_block, "next", flow_false, "prev"); +\`\`\` + +**If the If/Else block is inside a Loop block's \`$groupContents\`**, "JMP"/"HALT" would exit the loop +entirely (or halt the PRU) instead of continuing the loop — jump to the loop's own \`_start\` +target instead so the loop keeps iterating: +\`\`\`javascript +// if_else1 is one of the instances inside loop_block1.$groupContents +const flow_true = flow_control_block.addInstance(); +flow_true.$name = "Flow_Control_True_End"; +flow_true.jumpTarget = "Loop_0_start"; // for INFINITE loops, this continues cleanly; for finite loops it re-arms LOOP (not a true continue) +scripting.connect(true_path_block, "next", flow_true, "prev"); + +const flow_false = flow_control_block.addInstance(); +flow_false.$name = "Flow_Control_False_End"; +flow_false.jumpTarget = "Loop_0_start"; +scripting.connect(false_path_block, "next", flow_false, "prev"); +\`\`\` +Jumping to `_start` resumes the loop for INFINITE loops (clean continue), but for finite loops it re-arms LOOP (counter reloads). For behavior corresponding to `break` use the flow control to jump to the start label of the block connected next to the loop block, `Continue and Break implementation using Flow Control Blocks` section in docs/program-control/loop_block.md for full context and details + +### Important Notes + +1. **Two Inputs Required**: Both input1 and input2 must be connected for comparison. + +2. **Two Output Paths**: Connect blocks to both T (true) and F (false) ports. + +3. **Unsigned Comparison**: All comparisons treat values as unsigned integers. + +4. **Single Cycle**: Comparison and branch decision execute in 1 PRU cycle. + +5. **Port Names**: True path uses "T" port, False path uses "F" port (displayed as t_next/f_next). + +6. **Every Connected Branch MUST Terminate in a Flow Control Block**: The code generator places the FALSE path immediately after the branch instruction, with the TRUE path at the branch target label. If a connected branch (T or F) has no explicit terminator, execution falls through into the other branch — causing both to execute regardless of the condition. This is now enforced by SysConfig validation (an error, not a warning) — any connected T or F branch that doesn't end in a Flow Control block will fail validation. A branch left entirely unconnected is still fine (nothing happens on that path). + +7. **Where the Flow Control Block Should Jump To Depends On Context**: + - **Standalone If/Else** (not inside a Loop block): jump to \`JMP\` (SysConfig Generated End), \`HALT\`, or any other block's \`_start\` target. + - **If/Else nested inside a Loop block**: jump to that Loop's own \`_start\` target, so execution resumes the loop instead of exiting it. Using \`JMP\`/\`HALT\` here ends the whole program early instead of continuing the loop — only do that if that's actually the intent (e.g. an early-exit condition that should stop everything, not just this iteration). To break out of the loop early without ending the whole program, jump to the the start label of the block connected to the loop block's next port or sysconfig_generated_end/halt depending on the usecase \ No newline at end of file diff --git a/docs_ai/program_control/flow_control_block.md b/docs_ai/program_control/flow_control_block.md new file mode 100644 index 0000000..051f5b7 --- /dev/null +++ b/docs_ai/program_control/flow_control_block.md @@ -0,0 +1,146 @@ +## Flow Control Block + +### Purpose +Controls PRU program flow by jumping to the end of generated code, halting the PRU, or jumping to the entry point of any other block in the design. + +### How It Works +1. **Place in Flow**: Position this block where you want to control program flow +2. **Select Jump Target**: Pick from a single dropdown — Sysconfig Generated End, Halt, or the entry/exit point of any block in the design +3. **Execution**: When reached, performs the selected jump +4. **No Output**: This is a **terminating block** - no next connections + +### Configuration + +**Jump To**: A single dropdown listing every valid jump target in the current design: + +- **Sysconfig Generated End**: Jumps to the end label of the SysConfig-generated code. Allows any cleanup code or epilogue to execute. Recommended for normal program completion. Generated instruction: `JMP sysconfig_generated_end` +- **Halt**: Immediately stops the PRU execution. Puts PRU into halt state, no cleanup or epilogue runs. Generated instruction: `HALT`. Use for emergency stops or when no cleanup needed. +- **Any block's `_start`**: Every block in the design — ordinary blocks, If/Else blocks, Loop blocks, Group blocks — has an addressable `_start` entry point. The dropdown only lists real, currently-existing targets — SysConfig rejects the field if a previously-selected target no longer exists (e.g. the referenced block was renamed or deleted). + +### _start vs _end targets + +- Every block exposes `_start` — jump here to (re-)run that block. For a finite Loop, this re-arms LOOP (counter reloads, not a clean continue); for an infinite loop (`startloop_N` with `QBA`), it acts like a true continue. + +### Technical Details (Additional Information) + +**Generated Assembly** (Sysconfig Generated End): +```asm +JMP sysconfig_generated_end ; Jump to end label (1 cycle) +``` + +**Generated Assembly** (Halt): +```asm +HALT ; Halt immediately (1 cycle) +``` + +**Generated Assembly** (block target): +```asm +JMP Loop_0_start ; Jump to the selected block's entry/exit point (1 cycle) +``` + +**Performance**: Every jumpTarget option executes in 1 PRU cycle + +### Block Appearance +- **Shape**: Circle (distinct from square data processing blocks) +- **Icon**: Flow control symbol +- **No Output Ports**: Terminating block - execution stops here + +### Usage Notes +- This is a **terminating block** - it has no output connections +- Use Sysconfig Generated End for normal program exits (recommended default) +- Use Halt for emergency stops or when cleanup isn't needed +- Select any other block's entry/exit point directly from the same dropdown — no separate free-text field +- Multiple FLOW_CONTROL blocks can exist in different program paths +- **Every If/Else (Conditional) branch that is connected MUST end in a Flow Control block**: An If/Else block's TRUE and FALSE branches are NOT mutually exclusive in the generated assembly unless each branch is explicitly terminated — without a terminator, execution falls from one branch straight into the other and runs both. SysConfig now enforces this as a validation error, not just a warning — connect a Flow Control block (any jumpTarget) at the end of every connected T/F branch. + +### Terminology +- **Flow control**: Directing program execution path +- **Terminating block**: Block with no output - ends execution path +- **HALT**: PRU instruction that stops core execution +- **JMP**: Jump instruction that transfers control to a label +- **jumpTarget**: The single dropdown selecting where this block jumps to — Sysconfig Generated End, Halt, or any real `_start` target in the design, validated against the current design, not free text + +--- + +## How to Configure (For AI/Scripting) + +This section describes how to programmatically configure the Flow Control block in a .syscfg file. + +### Adding a Flow Control Instance + +\`\`\`javascript +const flow_control_block = scripting.addModule("/pru_blocks/program_control/flow_control_block", {}, false); +const flow1 = flow_control_block.addInstance(); +\`\`\` + +### Configuration Parameters + +| Parameter | Type | Valid Values | Default | Description | +|-----------|------|--------------|---------|-------------| +| jumpTarget | String | "JMP", "HALT", or the name of any real _start target in the design | "JMP" | Single dropdown covering every jump target — end of generated code, halt, or any block's entry point. Validated against the current design, not free text | + +### Valid Values for jumpTarget + +| Value | Display Name | Description | +|-------|--------------|-------------| +| "JMP" | Sysconfig Generated End | Jump to end label of generated code | +| "HALT" | Halt | Immediately stop PRU execution | +| "_start" | | Jump to that block's entry point | + +### _start targets + +- Every block exposes `_start` — jump here to (re-)run that block. For a finite Loop, this re-arms LOOP (counter reloads, not a clean continue); for an infinite loop (`startloop_N` with `QBA`), it acts like a true continue. + +### Example Configurations + +**Jump to end (normal exit):** +\`\`\`javascript +flow1.$name = "Flow_Control_End"; +flow1.jumpTarget = "JMP"; +\`\`\` + +**Halt PRU immediately:** +\`\`\`javascript +flow1.$name = "Flow_Control_Halt"; +flow1.jumpTarget = "HALT"; +\`\`\` + +**Jump to another block's entry point (e.g. re-entering a loop):** +\`\`\`javascript +flow1.$name = "Flow_Control_Custom"; +flow1.jumpTarget = "Loop_0_start"; // Must match a real "_start" target in the design — validated by SysConfig +\`\`\` + +**Break out of a loop (example):** +```javascript +// TRUE branch jumps to the next connected block (e.g. SPI read) to exit loop. +flow_break.$name = "Flow_Control_Break"; +flow_break.jumpTarget = "PRU0_SPI_Read_0_start"; // label of block after loop, lets say SPI read is connected to loop's next +scripting.connect(if_else_check, "T", flow_break, "prev"); +``` + +### Connecting to Other Blocks + +\`\`\`javascript +// Flow Control is a terminating block - only has prev port, no next +scripting.connect(prev_block, "next", flow1, "prev"); + +// Often used after conditional block's true or false path +scripting.connect(if_else1, "T", flow1, "prev"); // Exit on true condition +\`\`\` + +### Important Notes + +1. **Terminating Block**: Flow Control has no output ports - it ends the execution path. + +2. **No Next Port**: Cannot connect anything to this block's output - execution ends here. + +3. **JMP vs HALT vs a block target**: Use "SysConfig Generated End" for normal exits (allows cleanup code), "Halt" for immediate stops, or select any other block's entry directly from the same dropdown (e.g. an If/Else block's own `_start` to re-evaluate it, or a Loop block's `_start` to re-enter). + +4. **Single Cycle**: All jumpTarget options execute in 1 PRU cycle. + +5. **jumpTarget is validated against the current design**: Every block gets an addressable `_start` entry point, and the dropdown lists all of them alongside SysConfig Generated End / Halt — SysConfig rejects any value that doesn't correspond to a real target. If a referenced block is renamed or removed, re-select the target; SysConfig will flag it as invalid at validation time, not at the assembler build step. +### Validation Notes for AI Agents +- **Disconnected subgraphs**: Every disconnected block chunk must end in a Flow Control block. The validator checks this (`checkDisconnectedChunks`) and reports a warning per missing termination. +- **Dropdown filtering (Option A)**: Only labels actually emitted by the register allocator appear in the dropdown. Memory variables, lookup tables, and unreachable blocks are filtered out. +- **Unreachable chunks**: Post-simulation, unreachable emitted labels (`_start`, loop labels) trigger warnings (`Unreachable chunk: label 'X'...`). This is a warning, not an error. diff --git a/docs_ai/program_control/group_block.md b/docs_ai/program_control/group_block.md new file mode 100644 index 0000000..d3a6906 --- /dev/null +++ b/docs_ai/program_control/group_block.md @@ -0,0 +1,301 @@ +## Group Block (Code Organization Container) + +### Purpose +The Group Block allows you to organize related blocks into named, reusable sections that can be selectively executed from your main.asm firmware. This enables modular code organization where you have full control over which functionality executes and when. + +### Key Concept +Instead of all blocks executing sequentially in one flow, you can: +- **Group related functionality** together (e.g., ADC config, sensor initialization, data processing) +- **Execute groups selectively** by calling them from main.asm only when needed +- **Keep ungrouped blocks** in the default execution path (`sysconfig_generated_start/end`) + +--- + +## How To Use Group Blocks + +### Step 1: Create a Group Block +1. Add a **Group Block** from the program control palette +2. Give it a **meaningful name** (e.g., "adc_config", "sensor_init", "data_process") +- Must be a valid identifier (letters, numbers, underscore only) +- Cannot start with a number +- Must be unique across all groups + +### Step 2: Add Blocks Inside the Group +1. **Drag blocks** into the gray group container box +2. Connect blocks inside using their input/output/prev/next ports (same as normal) +3. The group acts as a visual container - all blocks inside will execute together when the group is called + +### Step 3: Call Groups from main.asm +Simply use the CALL macro to invoke groups - execution automatically continues after the call. + +**Example for a group named "ABC":** + +```asm +; In main.asm - declare the group start label + .ref ABC_start ; Reference the start label (defined in pru_syscfg.asm) + +main: + ; Your initialization code... + + ; Call the ABC group - execution automatically returns here + CALL ABC_start + ; No label needed! Execution continues here automatically + + ; You can call the same group multiple times + CALL ABC_start + ; Returns here again + + halt +``` + +**Important:** +- Use the CALL macro (defined in pru_syscfg.inc) instead of JAL directly +- Execution automatically returns to the next instruction after CALL +- No need to define end labels manually +- Groups can be called multiple times from anywhere in main.asm +- The CALL macro uses R27.w0 as the return address register + + +## Technical Details + +### Generated Labels +For a group named "my_group": +- **Start label**: `my_group_start` (declared as `.global` in pru_syscfg.asm) +- **No end label needed** - RET instruction automatically returns to caller + +### CALL/RET Pattern +Groups use standard subroutine calling convention: +- **CALL macro**: Uses JAL (Jump And Link) to save return address and jump to group +- **RET instruction**: Returns to the saved address +- **Return address register**: R27.w0 (RET_ADDR0) +- **Automatic return**: No manual label management required + +### Execution Flow +1. **Ungrouped blocks** are processed first and appear in the `sysconfig_generated_start` section +2. **Grouped blocks** are processed separately and appear AFTER the default section +3. Groups only execute when you explicitly call them from main.asm +4. Each group **automatically generates** a return instruction (`JMP RET_ADDR0`) at the end + +### Processing Order Inside Groups +Blocks inside groups follow the same execution order rules: +- **End blocks** (blocks with no output/next/T/F ports) process first +- **Unconnected next** blocks process second +- **Result nodes** (unconnected output ports) process third +- Data dependencies via input ports ensure correct evaluation order + +### Container Features +- **Resizable**: Default 500×250 pixels, drag corners to resize +- **Visual organization**: Gray box clearly shows which blocks belong to the group +- **Drag-and-drop**: Simply drag blocks into/out of the container +- **Nesting support**: Can contain Loop blocks, or be nested in other groups + +--- + +## Important Notes + +### Automatic Return Generation +Groups automatically generate a return instruction at the end: +- No Flow Control block required +- Return instruction (`JMP RET_ADDR0`) is automatically added +- Execution returns to the instruction after CALL +- Optional: You can still add Flow Control blocks inside groups for conditional exits or HALT + +### Ungrouped vs Grouped Blocks +- **Ungrouped blocks**: Execute automatically when you call `sysconfig_generated_start` +- **Grouped blocks**: Only execute when you explicitly call their start label +- Choose wisely what goes where based on your program flow + +### Label Naming +- Group names become assembly labels +- Use descriptive names: "adc_config" not "group1" +- Keep names concise (< 32 characters recommended) +- Follow C identifier rules (no spaces, no special chars except underscore) + +### Groups are Independent +- Groups don't automatically call each other +- Each group is a standalone code section +- You control the execution order from main.asm +- This gives you maximum flexibility + +--- + +## Comparison: Grouped vs Ungrouped + +| Feature | Ungrouped Blocks | Grouped Blocks | +|---------|------------------|----------------| +| Execution | Auto (when calling sysconfig_generated_start) | Manual (when you call group_start) | +| Use case | Initialization, always-needed code | Optional, conditional, or repeated functionality | +| Labels | sysconfig_generated_start/end | `groupName`_start (only) | +| Return Handling | JMP to sysconfig_generated_end | Automatic JMP RET_ADDR0 generated | +| Flexibility | Executes every time | Execute only when called | + +--- +## How to Configure (For AI/Scripting) + +This section describes how to programmatically configure the Group block in a .syscfg file. + +### Adding a Group Instance + +\`\`\`javascript +const group_block = scripting.addModule("/pru_blocks/program_control/group_block", {}, false); +const group_block1 = group_block.addInstance(); +\`\`\` + +### Configuration Parameters + +| Parameter | Type | Valid Values | Default | Description | +|-----------|------|--------------|---------|-------------| +| groupName | String | Valid identifier (letters, numbers, underscore) | "" | Unique name for the group (becomes assembly label) | +| $size | Array | [width, height] | [500, 250] | Size of the group container in pixels | + +### Naming Rules for groupName + +- Must be a valid C identifier +- Can contain letters (a-z, A-Z), numbers (0-9), and underscore (_) +- Cannot start with a number +- Must be unique across all groups +- Recommended: Keep under 32 characters + +### Example Configurations + +**Create a group with blocks inside:** +\`\`\`javascript +group_block1.$name = "Group_0"; +group_block1.groupName = "my_group"; +group_block1.$size = [500, 320]; +\`\`\` + +### Adding Blocks Inside the Group + +\`\`\`javascript +// Use $groupContents to specify which blocks are inside the group +group_block1.$groupContents = [load_constant_block3, load_constant_block4, conditional_block2, pru_gpo_block1, pru_gpo_block2]; +\`\`\` + +### Complete Example with Conditional Inside Group + +\`\`\`javascript +// Create blocks +const load_constant_block = scripting.addModule("/pru_blocks/data_handling/load_constant_block", {}, false); +const load_constant_block3 = load_constant_block.addInstance(); +const load_constant_block4 = load_constant_block.addInstance(); + +const conditional_block = scripting.addModule("/pru_blocks/program_control/conditional_block", {}, false); +const conditional_block2 = conditional_block.addInstance(); + +const pru_gpo_block = scripting.addModule("/pru_blocks/pru_io_blocks/pru_gpo_block", {}, false); +const pru_gpo_block1 = pru_gpo_block.addInstance(); +const pru_gpo_block2 = pru_gpo_block.addInstance(); + +const group_block = scripting.addModule("/pru_blocks/program_control/group_block", {}, false); +const group_block1 = group_block.addInstance(); + +// Configure blocks +load_constant_block3.$name = "Load_Constant_2"; +load_constant_block3.constant1 = 14; + +load_constant_block4.$name = "Load_Constant_3"; +load_constant_block4.constant1 = 15; + +conditional_block2.$name = "If_Else_1"; +conditional_block2.conditionToCheck = "lessThanEqualtoInput2"; + +pru_gpo_block1.$name = "PRU_GPO_0"; +pru_gpo_block2.$name = "PRU_GPO_1"; + +// Configure group +group_block1.$name = "Group_0"; +group_block1.groupName = "my_group"; +group_block1.$size = [500, 320]; + +// Add blocks inside the group +group_block1.$groupContents = [load_constant_block3, load_constant_block4, conditional_block2, pru_gpo_block1, pru_gpo_block2]; + +// Connect blocks inside the group +scripting.connect(load_constant_block3, "output1", conditional_block2, "input1"); +scripting.connect(load_constant_block4, "output1", conditional_block2, "input2"); +scripting.connect(conditional_block2, "T", pru_gpo_block1, "prev"); +scripting.connect(conditional_block2, "F", pru_gpo_block2, "prev"); + +// Set positions +group_block1.$position = [0, 150]; +load_constant_block3.$position = [60, 40]; +load_constant_block4.$position = [60, 105]; +conditional_block2.$position = [210, 65]; +pru_gpo_block1.$position = [360, 70]; +pru_gpo_block2.$position = [370, 130]; +\`\`\` + +### Calling Groups from main.asm + +\`\`\`asm +; In main.asm - declare and call the group + .ref my_group_start ; Reference the group's start label + +main: + CALL my_group_start ; Execute all blocks in the group + ; Execution automatically returns here + + CALL my_group_start ; Can call multiple times + + halt +\`\`\` + +### Important Notes + +1. **Container Block**: Group is a container - use $groupContents to add blocks inside. + +2. **No Ports**: Group blocks have no input/output ports - they define code sections. + +3. **Label Generation**: A group named "xyz" generates label "xyz_start" in assembly. + +4. **Automatic Return**: Groups automatically add return instruction - no Flow Control needed. + +5. **CALL Macro**: Use CALL (not JMP) to invoke groups so execution returns properly. + +6. **Independent Execution**: Groups only execute when explicitly called from main.asm. + +7. **Return Register**: The register allocator automatically allocates a register for the return address. + +--- + +## Critical Pitfalls (AI Must Read) + +### Pitfall 1: `groupName` is SEPARATE from `$name` — both must be set +The group block has two distinct name fields: +- `$name`: SysConfig instance identifier (e.g., "Group_0") — used internally by SysConfig +- `groupName`: generates the assembly label (e.g., "my_group" → `my_group_start`) — used in main.asm + +Leaving `groupName` empty causes a **build error**: "Group name cannot be empty". +Always set both in the .syscfg file: +\`\`\`javascript +group_block1.$name = "Group_0"; +group_block1.groupName = "my_group"; // REQUIRED - do not omit +\`\`\` + +### Pitfall 2: `$groupContents` CANNOT be set via `changeConfiguration` MCP tool +The `changeConfiguration` tool does not support `$groupContents`. It must be set by directly +editing the .syscfg file: +\`\`\`javascript +group_block1.$groupContents = [load_constant_block1, access_look_up_table1]; +\`\`\` +After calling `changeConfiguration` and `save`, always re-read the .syscfg file to verify +`$groupContents` was written correctly and add it manually if missing. + +### Pitfall 3: main.asm MUST `.include "pru_syscfg.inc"` to use CALL +`CALL` is a macro defined in `pru_syscfg.inc` (expands to `JAL RET_ADDR0, func`). +It is NOT a native PRU instruction. Without the include, the assembler errors with: +"[E0003] Invalid instruction: CALL". +Add this at the top of main.asm before any group calls: +\`\`\`asm + .include "pru_syscfg.inc" + .ref my_group_start +\`\`\` + +### Pitfall 4: Register allocation SHIFTS when blocks move into a Group +The group return address uses `R0.w0` (low 16 bits = `R0.b0` + `R0.b1`). +To avoid collision, the allocator shifts data registers up (e.g., `R0.b0`/`R0.b1` → `R0.b2`/`R0.b3`). +**After any structural change** (adding/removing a group, moving blocks in/out): +1. Rebuild the project +2. Re-read the Register Allocation Summary in the generated `pru_syscfg.asm` +3. Update all `SBBO` / `LBBO` register references in main.asm accordingly \ No newline at end of file diff --git a/docs_ai/program_control/loop_block.md b/docs_ai/program_control/loop_block.md new file mode 100644 index 0000000..c8205b1 --- /dev/null +++ b/docs_ai/program_control/loop_block.md @@ -0,0 +1,270 @@ +## Loop Block (Repetition Control) + +### Purpose +Repeats a sequence of blocks multiple times. This is a container block that executes all blocks inside it for a specified number of iterations or infinitely. + +### How It Works +1. **Place Blocks Inside**: Drag and drop blocks into the LOOP container (the gray box) +2. **Configure Iterations**: Set loop count or enable infinite loop +3. **Execution**: All blocks inside the loop execute sequentially based on the next port to prev port connection.If prev and next port are disconnected then blocks execute based on their input dependency. +4. **Exit**: After all iterations complete, execution continues to blocks connected to the next port + +### Configuration + +**Infinite Loop**: Checkbox option +- **Unchecked** (default): Loop runs for specified count, then continues +- **Checked**: Loop runs forever - program stays in loop indefinitely +- Warning: Infinite loops never exit, so the next port is hidden +- Use with caution - ensure you want the PRU to loop forever + +**Loop Count**: Number of iterations (1 to 65,535) +- Only visible when Infinite Loop is unchecked +- Determines how many times the loop body executes +- Range: 1 to 0xFFFF (16-bit, limited by PRU LOOP instruction) + +**Pre-Initialization Blocks**: Multi-select dropdown +- Select blocks whose instructions should execute ONCE before the loop starts, not on every iteration +- Useful for initializing accumulators, counters, or one-time setup operations +- Selected blocks are still inside the loop visually, but their code is moved outside + +**Common Use Cases for Pre-Initialization**: +1. **Accumulator Pattern**: Initialize a variable to 0 before accumulating values across iterations +2. **Counter Initialization**: Set starting value for a counter that increments each iteration +3. **Configuration Setup**: One-time register or peripheral configuration before repeated operations + +**Example - Sending Incrementing Values (0,1,2,3...) over SPI**: +- Load_Constant_0 (value 0) → Mark as pre-init (initial accumulator value) +- Load_Constant_1 (value 1) → Leave in loop (increment value) +- Arithmetic_0 (ADD) → Accumulates: result = result + 1 +- SPI_Write → Sends accumulated value + +Without pre-init: Sends 1,1,1,1,1... (accumulator resets to 0 each iteration) +With Load_Constant_0 as pre-init: Sends 1,2,3,4,5... (accumulator initialized once) + +### Technical Details (Additional Information) + +**Generated Assembly** (Fixed count loop without pre-init): +```asm +; Initialize loop counter +LDI loop_counter, loop_count ; Load iteration count (1-2 cycles) +LOOP endloop_label, loop_counter ; Hardware loop instruction +; ... blocks inside loop execute here ... +endloop_label: +; Continue after loop +``` + +**Generated Assembly** (Fixed count loop WITH pre-init): +```asm +; Pre-initialization blocks execute ONCE here (before loop) +LDI R0.b1, 0 ; Example: Initialize accumulator + +; Initialize loop counter +LDI loop_counter, loop_count ; Load iteration count +LOOP endloop_label, loop_counter ; Hardware loop instruction +; ... remaining blocks inside loop execute here ... +LDI R0.b2, 1 ; Example: Increment value +ADD R0.b1, R0.b1, R0.b2 ; Accumulate: R0.b1 = R0.b1 + 1 +endloop_label: +; Continue after loop (R0.b1 now contains accumulated result) +``` + +**Generated Assembly** (Infinite loop): +```asm +; Pre-initialization blocks (if any) execute ONCE here +startloop_label: +; ... blocks inside loop execute here ... +QBA startloop_label ; Unconditional jump back +; No code after this - never reached +``` + +**Performance**: +- Fixed loop overhead: 2-3 cycles (counter initialization) +- Per-iteration overhead: 2 cycles (decrement + branch check) +- Infinite loop overhead: 1 cycle per iteration (unconditional jump) +- Total cycles = overhead + (loop_count × body_cycles) + +**Loop Counter Register**: Automatically sized based on loop count +- 1-255: 1 byte register +- 256-65535: 2 byte register + +### Container Block Behavior + +**Visual Layout**: +- Loop block appears as a resizable gray box +- Drag blocks inside the loop boundary to include them +- Blocks inside execute in sequence from prev to next +- Default size: 500×250 pixels (can be resized) + +**Block Order Inside Loop**: +Blocks execute in the order they are connected via prev/next ports within the loop container. + +### Usage Notes +- Loop block is a **container** - place other blocks inside it +- All blocks inside the loop execute in sequence each iteration +- Use **Pre-Initialization Blocks** for one-time setup (accumulators, counters) +- Pre-init blocks are processed during code generation - their instructions move outside the loop automatically +- Register allocation/deallocation happens normally - pre-init just reorders the generated instructions +- Infinite loops are useful for continuous monitoring or periodic tasks +- Be careful with infinite loops - they never exit +- Loop counter uses a register - this register is reserved during loop execution +- Nested loops are possible (place a LOOP block inside another LOOP block) +- Loop overhead is minimal (2-3 cycles setup, 2 cycles per iteration) + +### Performance Calculation + +**Formula**: +- Total cycles = Loop_overhead + (Loop_count × Body_cycles) + +Where: +- Loop_overhead = 2-3 cycles (counter initialization) +- Body_cycles = sum of cycles for all blocks inside loop +- Loop_count = number of iterations + +**Example**: +- Loop count: 100 +- Body: Load Constant (1 cycle) + Delay(10) (10 cycles) = 11 cycles +- Total = 3 + (100 × 11) = 1103 cycles +- At 200MHz: 1103 × 5ns = 5.515 microseconds + +### Terminology +- **Loop**: Programming construct that repeats a sequence of operations +- **Iteration**: One execution of the loop body +- **Loop counter**: Variable tracking how many iterations remain +- **Loop body**: The code/blocks executed each iteration +- **Infinite loop**: Loop that never terminates (runs forever) +- **Container block**: Block that contains other blocks (like a group) +- **Nested loop**: Loop inside another loop +- **Loop overhead**: Extra cycles required for loop management + +--- + +## How to Configure (For AI/Scripting) + +This section describes how to programmatically configure the Loop block in a .syscfg file. + +### Adding a Loop Instance + +\`\`\`javascript +const loop_block = scripting.addModule("/pru_blocks/program_control/loop_block", {}, false); +const loop_block1 = loop_block.addInstance(); +\`\`\` + +### Configuration Parameters + +| Parameter | Type | Valid Values | Default | Description | +|-----------|------|--------------|---------|-------------| +| infiniteLoop | Boolean | true, false | false | Enable infinite loop mode | +| loopCount | Integer | 1-65535 (0x1-0xFFFF) | 1 | Number of iterations (hidden if infiniteLoop=true) | +| preInitBlocks | Array | Block $name values inside loop | [] | Blocks to execute once before loop starts | +| $size | Array | [width, height] | [500, 250] | Size of the loop container in pixels | + +### Example Configurations + +**Fixed count loop (100 iterations):** +\`\`\`javascript +loop_block1.$name = "Loop_0"; +loop_block1.infiniteLoop = false; +loop_block1.loopCount = 100; +loop_block1.$size = [500, 290]; +\`\`\` + +**Infinite loop (runs forever):** +\`\`\`javascript +loop_block1.$name = "Main_Loop"; +loop_block1.infiniteLoop = true; +// Note: loopCount is ignored when infiniteLoop is true +\`\`\` + +**Loop with pre-initialization blocks:** +\`\`\`javascript +// Pre-init blocks execute ONCE before the loop starts, not on every iteration +loop_block1.$name = "Loop_0"; +loop_block1.loopCount = 10; +loop_block1.preInitBlocks = ["If_Else_0", "Load_Constant_1", "PRU_GPI_0"]; +\`\`\` + +### Adding Blocks Inside the Loop + +\`\`\`javascript +// Use $groupContents to specify which blocks are inside the loop +loop_block1.$groupContents = [load_constant_block1, load_constant_block2, conditional_block1, pru_gpi_block1, pru_gpi_block2]; +\`\`\` + +### Complete Example with Conditional Inside Loop + +\`\`\`javascript +// Create blocks +const load_constant_block = scripting.addModule("/pru_blocks/data_handling/load_constant_block", {}, false); +const load_constant_block1 = load_constant_block.addInstance(); +const load_constant_block2 = load_constant_block.addInstance(); + +const conditional_block = scripting.addModule("/pru_blocks/program_control/conditional_block", {}, false); +const conditional_block1 = conditional_block.addInstance(); + +const pru_gpi_block = scripting.addModule("/pru_blocks/pru_io_blocks/pru_gpi_block", {}, false); +const pru_gpi_block1 = pru_gpi_block.addInstance(); +const pru_gpi_block2 = pru_gpi_block.addInstance(); + +const loop_block = scripting.addModule("/pru_blocks/program_control/loop_block", {}, false); +const loop_block1 = loop_block.addInstance(); + +// Configure blocks +load_constant_block1.$name = "Load_Constant_0"; +load_constant_block1.constant1 = 5; + +load_constant_block2.$name = "Load_Constant_1"; +load_constant_block2.constant1 = 10; + +conditional_block1.$name = "If_Else_0"; +conditional_block1.conditionToCheck = "notEqualToInput2"; + +pru_gpi_block1.$name = "PRU_GPI_0"; +pru_gpi_block2.$name = "PRU_GPI_1"; + +// Configure loop with pre-init blocks +loop_block1.$name = "Loop_0"; +loop_block1.loopCount = 1; +loop_block1.preInitBlocks = ["If_Else_0", "Load_Constant_1", "PRU_GPI_0"]; +loop_block1.$size = [500, 290]; + +// Add blocks inside the loop +loop_block1.$groupContents = [load_constant_block1, load_constant_block2, conditional_block1, pru_gpi_block1, pru_gpi_block2]; + +// Connect blocks +scripting.connect(load_constant_block1, "output1", conditional_block1, "input1"); +scripting.connect(load_constant_block2, "output1", conditional_block1, "input2"); +scripting.connect(conditional_block1, "T", pru_gpi_block1, "prev"); +scripting.connect(conditional_block1, "F", pru_gpi_block2, "prev"); + +// Set positions +loop_block1.$position = [0, 0]; +load_constant_block1.$position = [105, 55]; +load_constant_block2.$position = [105, 120]; +conditional_block1.$position = [245, 70]; +pru_gpi_block1.$position = [395, 65]; +pru_gpi_block2.$position = [400, 130]; +\`\`\` + +### Connecting to Other Blocks + +\`\`\`javascript +// Connect control flow into the loop +scripting.connect(prev_block, "next", loop_block1, "prev"); + +// Connect control flow out of the loop (only for non-infinite loops) +scripting.connect(loop_block1, "next", next_block, "prev"); +\`\`\` + +### Important Notes + +1. **Container Block**: Loop is a container - use $groupContents to add blocks inside. + +2. **Max Iterations**: Maximum loop count is 65,535 (16-bit limit). Use nested loops for more. + +3. **Infinite Loop**: When infiniteLoop=true, the next port is hidden and loop never exits. + +4. **Pre-Initialization**: Use preInitBlocks with block $name values (as strings) for blocks that should execute once before the loop starts. Useful for initializing accumulators or one-time setup. + +5. **Loop Overhead**: Fixed loops add 2 cycles overhead (onetime) for finite loops, for infinite loops, its 1 cycle overhead per iteration + +6. **Nested Loops**: Place a Loop block inside another Loop for nested iteration. \ No newline at end of file diff --git a/docs_ai/pru_io_blocks/pru_gpi_block.md b/docs_ai/pru_io_blocks/pru_gpi_block.md new file mode 100644 index 0000000..c875765 --- /dev/null +++ b/docs_ai/pru_io_blocks/pru_gpi_block.md @@ -0,0 +1,175 @@ +## PRU GPI Block (General Purpose Input) + +### Purpose +Reads digital input signals from PRU input pins and outputs the pin state to the next block. + +### How It Works +1. **Select Pin**: Choose which PRU input pin to read (PRU_GPI_0 through PRU_GPI_19) +2. **Read Operation**: Generates an AND instruction to mask and read the specific bit from R31 register +3. **Output**: Provides the pin value (0 or 1) to the next block + +### Configuration +- **PRU GPI Signal**: Select the input pin number (0-19) + - Each pin maps to a specific bit in the R31 register + - PRU_GPI_0 = bit 0, PRU_GPI_1 = bit 1, etc. + +### Technical Details (Additional Information) +**Generated Assembly**: +- AND result, R31, (1 << pin_number) ; Mask the specific bit (1 cycle) + +**Performance**: 1 PRU cycle + +**Register**: R31 is the PRU's input register +- Read-only register +- Reflects current state of PRU input pins +- Updated automatically by hardware + +### Pin Mapping +The PRU_GPI pins map to physical device pins based on your board's pin mux configuration. Check your device's technical reference manual for exact pin mappings. + +### Usage Examples + +**Example 1: Reading a button state** +``` +PRU GPI Block configured for PRU_GPI_5 + ↓ (outputs button state: 1=pressed, 0=released) +Next block processes button state +``` + +**Example 2: Reading multiple sensors** +``` +PRU GPI (pin 0) → Sensor 1 state +PRU GPI (pin 1) → Sensor 2 state +PRU GPI (pin 2) → Sensor 3 state +``` + +**Example 3: Monitoring a UART RX line** +``` +PRU GPI (pin 14) → UART RX signal state → Process in custom code +``` + +### Simulating Input Data + +To test PRU GPI without hardware, use the **Simulation Settings** module to simulate pin state changes on R31: + +**Simulation Setup:** +1. **Open Simulation Settings**: Navigate to the Simulation Settings module +2. **Select R31 Pin**: In "Select R31 (Input) Signals", select the pin configured for GPI +3. **Configure Input Mode**: Choose Timestamp Mode or Pattern Mode +4. **Define Pin States**: Enter when the pin should be HIGH (1) or LOW (0) + +**Example - Simulating button press on PRU_GPI_5:** +``` +R31 Bit 5 - Timestamp Mode: + Input Cycles: [0, 100, 200, 300] + Input Values: [0, 1, 1, 0] + + Interpretation: + - Cycles 0-99: Button released (0) + - Cycles 100-199: Button pressed (1) + - Cycles 200-299: Button still pressed (1) + - Cycles 300+: Button released (0) +``` + +**Example - Simulating PWM signal on PRU_GPI_3:** +``` +R31 Bit 3 - Pattern Mode: + Pattern: 1111110000111111000011111100001111110000 + + Simulates a 60% duty cycle PWM signal +``` + +**Example - Simulating sensor transitions:** +``` +R31 Bit 10 - Timestamp Mode: + Input Cycles: [50, 150, 250, 350, 450] + Input Values: [1, 0, 1, 0, 1] + + Simulates sensor detecting presence at specific time intervals +``` + +**Viewing Results:** +- Monitor the output value from the GPI block +- Verify the masked bit value matches expected R31 state +- Check that transitions occur at the configured cycle times +- Use waveform view to visualize input signal timing + +### Terminology +- **GPI**: General Purpose Input +- **R31**: PRU input register (32-bit, read-only) +- **Bit masking**: Using AND operation to isolate a specific bit +- **Pin mux**: Pin multiplexer - configures physical pins for different functions +- **Pull-up/Pull-down**: Resistor that sets default pin state when not driven +- **Debouncing**: Filtering technique to remove noise from mechanical switches +- **Floating**: Unconnected pin that can randomly read 0 or 1 + +--- + + +## How to Configure (For AI/Scripting) + +This section describes how to programmatically configure the PRU GPI block in a .syscfg file. + +### Adding a PRU GPI Instance + +\`\`\`javascript +const pru_gpi_block = scripting.addModule("/pru_blocks/pru_io_blocks/pru_gpi_block", {}, false); +const gpi1 = pru_gpi_block.addInstance(); +\`\`\` + +### Configuration Parameters + +| Parameter | Type | Valid Values | Default | Description | +|-----------|------|--------------|---------|-------------| +| constant1 | String | "R31, 1 << 0" to "R31, 1 << 19" | "R31, 1 << 0" | PRU GPI pin selection (bit mask) | + +### Valid Values for constant1 + +| Value | Display Name | Description | +|-------|--------------|-------------| +| "R31, 1 << 0" | PRU_GPI_0 | Read input pin 0 | +| "R31, 1 << 1" | PRU_GPI_1 | Read input pin 1 | +| "R31, 1 << 2" | PRU_GPI_2 | Read input pin 2 | +| ... | ... | ... | +| "R31, 1 << 19" | PRU_GPI_19 | Read input pin 19 | + +### Example Configurations + +**Read from PRU_GPI_0:** +\`\`\`javascript +gpi1.$name = "PRU_GPI_0"; +gpi1.constant1 = "R31, 1 << 0"; +\`\`\` + +**Read from PRU_GPI_5 (button input):** +\`\`\`javascript +gpi1.$name = "Button_Input"; +gpi1.constant1 = "R31, 1 << 5"; +\`\`\` + +**Read from PRU_GPI_14 (UART RX line):** +\`\`\`javascript +gpi1.$name = "UART_RX_Monitor"; +gpi1.constant1 = "R31, 1 << 14"; +\`\`\` + +### Connecting to Other Blocks + +\`\`\`javascript +// Connect GPI output to downstream processing block +scripting.connect(gpi1, "output1", process_block, "input1"); + +// Connect control flow +scripting.connect(prev_block, "next", gpi1, "prev"); +scripting.connect(gpi1, "next", next_block, "prev"); +\`\`\` + +### Important Notes + +1. **Output**: The GPI block outputs the masked bit value from R31 (either 0 or non-zero based on pin state). + +2. **Pin Mux**: Physical pin must be configured as PRU GPI in pin mux settings. + +3. **Read-Only**: R31 is a read-only register that reflects current pin states. + +4. **Single Cycle**: Reading takes only 1 PRU cycle. \ No newline at end of file diff --git a/docs_ai/pru_io_blocks/pru_gpo_block.md b/docs_ai/pru_io_blocks/pru_gpo_block.md new file mode 100644 index 0000000..8105870 --- /dev/null +++ b/docs_ai/pru_io_blocks/pru_gpo_block.md @@ -0,0 +1,220 @@ +## PRU GPO Block (General Purpose Output) + +### Purpose +Sets or clears digital output signals on PRU output pins. This is a terminating block that directly controls physical pin states. + +### How It Works +1. **Select Pin**: Choose which PRU output pin to control (PRU_GPO_0 through PRU_GPO_19) +2. **Select Operation**: Choose SET (HIGH) or CLEAR (LOW) +3. **Execute**: Generates SET/CLR instruction to change the pin state immediately + +### Configuration +- **PRU GPO Signal**: Select the output pin number (0-19) +- Each pin maps to a specific bit in the R30 register +- PRU_GPO_0 = bit 0, PRU_GPO_1 = bit 1, etc. +- **Output Operation**: +- **SET SIGNAL**: Sets the pin HIGH (logic 1) +- **CLEAR SIGNAL**: Sets the pin LOW (logic 0) + +### Technical Details (Additional Information) +**Generated Assembly**: +- SET R30, pin_number ; Set pin HIGH (1 cycle) +- ; OR +- CLR R30, pin_number ; Set pin LOW (1 cycle) + +**Performance**: 1 PRU cycle + +**Register**: R30 is the PRU's output register +- Write-only register +- Controls state of PRU output pins +- Changes take effect immediately + +### Usage Notes +- This is a **terminating block** - it has no output connections +- Multiple GPO blocks can control different pins independently +- Pin states persist until explicitly changed +- Physical pin behavior depends on pin mux configuration + +### Pin Mapping +The PRU_GPO pins map to physical device pins based on your board's pin mux configuration. Check your device's technical reference manual for exact pin mappings. + +### Usage Examples + +**Example 1: Controlling an LED** +``` +[Some condition check] → PRU GPO (pin 5, SET) + Turns LED ON + +[Another condition] → PRU GPO (pin 5, CLR) + Turns LED OFF +``` + +**Example 2: Generating a chip select signal** +``` +Start of SPI transaction: +PRU GPO (CS pin, CLR) → Assert CS (active low) + +[SPI data transfer blocks] + +End of SPI transaction: +PRU GPO (CS pin, SET) → Deassert CS (return to idle high) +``` + +**Example 3: Creating a pulse/strobe signal** +``` +PRU GPO (pin 10, SET) → Set pulse HIGH +[Delay block] +PRU GPO (pin 10, CLR) → Set pulse LOW + +Generates a pulse of configurable width +``` + +**Example 4: Multi-bit parallel output** +``` +PRU GPO (pin 0, SET/CLR) → Bit 0 of parallel bus +PRU GPO (pin 1, SET/CLR) → Bit 1 of parallel bus +PRU GPO (pin 2, SET/CLR) → Bit 2 of parallel bus +PRU GPO (pin 3, SET/CLR) → Bit 3 of parallel bus + +Creates a 4-bit parallel output port +``` + +**Example 5: Status/debug indicators** +``` +[Error detected] → PRU GPO (error LED pin, SET) +[Normal operation] → PRU GPO (error LED pin, CLR) +[Busy processing] → PRU GPO (busy LED pin, SET) +[Idle] → PRU GPO (busy LED pin, CLR) +``` + +**Example 6: GPIO bit-banging protocols** +``` +I2C Clock (SCL): +PRU GPO (SCL pin, SET/CLR) at appropriate times + +I2C Data (SDA): +PRU GPO (SDA pin, SET/CLR) for data transmission +(Note: Need to switch to input mode for reading) +``` + +### Terminology +- **GPO**: General Purpose Output +- **R30**: PRU output register (32-bit, write-only) +- **SET**: Instruction that sets a bit to 1 (HIGH) +- **CLR**: Instruction that clears a bit to 0 (LOW) +- **Pin mux**: Pin multiplexer - configures physical pins for different functions +- **Terminating block**: Block with no output connections to other blocks +- **Bit-banging**: Software-controlled pin toggling to implement protocols +- **Current drive**: Maximum current a pin can source or sink +- **Open-drain**: Output configuration requiring external pull-up resistor +- **Logic level**: Voltage representing HIGH (1) or LOW (0) state +- **Pull-up/Pull-down**: Resistor that sets default pin state when not actively driven + +--- + +## How to Configure (For AI/Scripting) + +This section describes how to programmatically configure the PRU GPO block in a .syscfg file. + +### Adding a PRU GPO Instance + +\`\`\`javascript +const pru_gpo_block = scripting.addModule("/pru_blocks/pru_io_blocks/pru_gpo_block", {}, false); +const gpo1 = pru_gpo_block.addInstance(); +\`\`\` + +### Configuration Parameters + +| Parameter | Type | Valid Values | Default | Description | +|-----------|------|--------------|---------|-------------| +| constant1 | String | "R30, 0" to "R30, 19" | "R30, 0" | PRU GPO pin selection | +| opCode | String | "SET", "CLR" | "SET" | Output operation (SET=HIGH, CLR=LOW) | + +### Valid Values for constant1 + +| Value | Display Name | Description | +|-------|--------------|-------------| +| "R30, 0" | PRU_GPO_0 | Control output pin 0 | +| "R30, 1" | PRU_GPO_1 | Control output pin 1 | +| "R30, 2" | PRU_GPO_2 | Control output pin 2 | +| ... | ... | ... | +| "R30, 19" | PRU_GPO_19 | Control output pin 19 | + +### Valid Values for opCode + +| Value | Display Name | Description | +|-------|--------------|-------------| +| "SET" | SET SIGNAL | Sets the pin HIGH (logic 1) | +| "CLR" | CLEAR SIGNAL | Sets the pin LOW (logic 0) | + +### Example Configurations + +**Set PRU_GPO_0 HIGH:** +\`\`\`javascript +gpo1.$name = "PRU_GPO_0_Set"; +gpo1.constant1 = "R30, 0"; +gpo1.opCode = "SET"; +\`\`\` + +**Clear PRU_GPO_5 (turn LED OFF):** +\`\`\`javascript +gpo1.$name = "LED_Off"; +gpo1.constant1 = "R30, 5"; +gpo1.opCode = "CLR"; +\`\`\` + +**Assert chip select (active low):** +\`\`\`javascript +gpo1.$name = "CS_Assert"; +gpo1.constant1 = "R30, 10"; +gpo1.opCode = "CLR"; +\`\`\` + +**Deassert chip select:** +\`\`\`javascript +gpo1.$name = "CS_Deassert"; +gpo1.constant1 = "R30, 10"; +gpo1.opCode = "SET"; +\`\`\` + +### Connecting to Other Blocks + +\`\`\`javascript +// GPO is a terminating block - no output connection +// Connect control flow only +scripting.connect(prev_block, "next", gpo1, "prev"); +scripting.connect(gpo1, "next", next_block, "prev"); +\`\`\` + +### Creating a Pulse + +\`\`\`javascript +// Create SET and CLR blocks for pulse generation +const pru_gpo_block = scripting.addModule("/pru_blocks/pru_io_blocks/pru_gpo_block", {}, false); +const gpo_set = pru_gpo_block.addInstance(); +const gpo_clr = pru_gpo_block.addInstance(); + +gpo_set.$name = "Pulse_High"; +gpo_set.constant1 = "R30, 3"; +gpo_set.opCode = "SET"; + +gpo_clr.$name = "Pulse_Low"; +gpo_clr.constant1 = "R30, 3"; +gpo_clr.opCode = "CLR"; + +// Connect in sequence: SET -> delay -> CLR +scripting.connect(gpo_set, "next", delay_block, "prev"); +scripting.connect(delay_block, "next", gpo_clr, "prev"); +\`\`\` + +### Important Notes + +1. **Terminating Block**: GPO has no output port - it only controls physical pins. + +2. **Pin Mux**: Physical pin must be configured as PRU GPO in pin mux settings. + +3. **Single Cycle**: SET/CLR operations take only 1 PRU cycle. + +4. **Persistence**: Pin state persists until explicitly changed by another GPO block. + +5. **Multiple Pins**: Use separate GPO instances to control different pins. \ No newline at end of file diff --git a/docs_ai/pru_io_blocks/pru_spi_read.md b/docs_ai/pru_io_blocks/pru_spi_read.md new file mode 100644 index 0000000..1492953 --- /dev/null +++ b/docs_ai/pru_io_blocks/pru_spi_read.md @@ -0,0 +1,276 @@ +## PRU SPI Read Block + +### Purpose +Implements SPI (Serial Peripheral Interface) protocol to read data in both Controller and Peripheral modes using bit-banging on PRU GPIO pins. + +### How It Works + +**Controller Mode:** +1. **Configure Pins**: Select SCLK (clock output), SDI (data input), and CS (chip select output) pins +2. **Set Timing**: Configure clock pulse widths, setup/hold times, and packet size +3. **Execute**: Generates bit-banged SPI read sequence with proper timing +4. **Output**: Provides received data to the next block + +**Peripheral Mode:** +1. **Configure Pins**: Select SCLK (clock input), SDI (data input), and CS (chip select input) pins +2. **Set Mode**: Configure SPI mode (MODE0-3), packet size, and CS filter cycles +3. **Execute**: Waits for CS assertion and controller clock, then reads data +4. **Output**: Provides received data to the next block + +### SPI Protocol +SPI is a synchronous serial communication protocol with: +- **SCLK (Serial Clock)**: Clock signal (Controller generates, Peripheral follows) +- **SDI (Serial Data In)**: Data line from device to PRU +- **CS (Chip Select)**: Activates the peripheral device (active low) +- **Modes**: Determines clock polarity (CPOL) and phase (CPHA) + +### Configuration Parameters + +**Device Mode**: Select Controller or Peripheral operation mode + +**SPI Mode**: Select MODE0-3 based on clock polarity and phase +- **MODE0** (CPOL=0, CPHA=0): Clock idles low, data sampled on rising edge, shifted on falling edge +- **MODE1** (CPOL=0, CPHA=1): Clock idles low, data sampled on falling edge, shifted on rising edge +- **MODE2** (CPOL=1, CPHA=0): Clock idles high, data sampled on falling edge, shifted on rising edge +- **MODE3** (CPOL=1, CPHA=1): Clock idles high, data sampled on rising edge, shifted on falling edge + +**Packet Size**: Number of bits to read (8-32) +- 8 bits = 1 byte (most common) +- 16 bits = 2 bytes +- 32 bits = 4 bytes (maximum) + +**Endianness**: Bit order +- **Most significant bit first** (MSB): Standard SPI, bit 7 → bit 0 +- **Least significant bit first** (LSB): Bit 0 → bit 7 + +**CS Signal**: Select PRU_GPO (Controller) or PRU_GPI (Peripheral) pin for chip select + +**SCLK Signal**: Select PRU_GPO (Controller) or PRU_GPI (Peripheral) pin for clock + +**SDI Signal**: Select PRU_GPI pin for data input + +### Clock Timing (Controller Mode Only) +- **SCLK High Width**: PRU cycles clock stays HIGH +- **SCLK Low Width**: PRU cycles clock stays LOW +- **Cycle Period**: Depends on PRU Clock Frequency (should be configured from R5F core and update same frequency in Simulation Settings to use while simulation) +- 200 MHz: 1 cycle = 5ns +- 250 MHz: 1 cycle = 4ns +- 333.333 MHz: 1 cycle = 3ns +- **Example** (at 333.333 MHz): High=7, Low=7 → 14 cycles per bit → ~23.8MHz SPI clock +- **Example** (at 200 MHz): High=7, Low=7 → 14 cycles per bit → ~14.3MHz SPI clock +- The **SPI Clock Frequency** field below automatically calculates the actual frequency based on your configured PRU clock +- Peripheral mode follows controller's clock timing + +### Maximum Achievable Frequency +Different SPI modes have different minimum SCLK width requirements due to timing overhead. +Cycles per bit: **(2+d1) + (5+d2)** + +**Theoretical Maximum (d1=0, d2=0 — controller overhead only):** +- **MODE0**: Min High=4, Min Low=3 → 200 MHz = 28.57 MHz | 333 MHz = 47.57 MHz (Total: 7 cycles) +- **MODE1**: Min High=1, Min Low=6 → 200 MHz = 28.57 MHz | 333 MHz = 47.57 MHz (Total: 7 cycles) +- **MODE2**: Min High=3, Min Low=4 → 200 MHz = 28.57 MHz | 333 MHz = 47.57 MHz (Total: 7 cycles) +- **MODE3**: Min High=6, Min Low=1 → 200 MHz = 28.57 MHz | 333 MHz = 47.57 MHz (Total: 7 cycles) + +**Practical Maximum (d1=10, d2=7 — recommended for reliable operation):** +- All modes: Min High+Low = 24 cycles → **200 MHz = 8.33 MHz** | **333 MHz = 13.88 MHz** + +**Note**: Theoretical maximums assume ideal peripheral response. Practical values (d1=10, d2=7) are recommended for reliable operation and are validated against the open-pru SPI slave macros. Actual maximum frequency depends on peripheral device specifications, signal integrity, and PCB layout. Always verify with oscilloscope and increase pulse widths if data corruption occurs. + +### Setup and Hold Times (Controller Mode Only) + +- **CS Setup Time**: Time delay (in nanoseconds) after CS assertion before starting SPI transaction. This ensures the peripheral device is ready before data transfer begins. +- **CS Hold Time**: Time delay (in nanoseconds) after the last bit is transferred before CS deassertion. This ensures the peripheral device has latched the data properly. +- **Data Setup Time**: Minimum time (in nanoseconds) MISO data must be stable before the sampling clock edge. Nops are inserted before the sampling edge. Automatically converted to PRU cycles internally using Math.ceil. + +**Note**: CS Setup Time, CS Hold Time, and Data Setup Time are all specified in **nanoseconds** and automatically converted to PRU cycles based on the PRU Clock Frequency configured in **Simulation Settings**. Ensure the PRU Clock Frequency matches your hardware configuration for accurate timing. + +### Peripheral Mode Parameters +- **CS Filter Cycles**: Number of consecutive cycles CS must be stable to be considered valid. This provides glitch rejection for noisy CS signals. + +### Technical Details (Additional Information) + +**Performance**: +- Cycles per bit ≈ (high_width + low_width + data_setup_time + overhead) +- Total cycles ≈ CS_setup + (packet_size × cycles_per_bit) + CS_hold + +### SPI Communication +**Typical SPI Transaction**: +1. Controller asserts CS (waits CS Setup Time) +2. Controller generates clock on SCLK +3. On each clock edge, peripheral outputs one bit on SDI +4. PRU samples SDI after Data Setup Time and stores the bit +5. Repeat for all bits in packet +6. Controller waits CS Hold Time, then deasserts CS + +### Usage Notes +- No hardware SPI - uses GPIO bit-banging for flexibility +- Clock timing directly controls SPI speed +- Setup and hold times should match peripheral device datasheet requirements +- Ensure peripheral device supports the configured SPI mode and speed +- Physical pins must be configured via pin mux + +### Simulating Input Data + +To test SPI Read without hardware, use the **Simulation Settings** module to simulate the SDI (Serial Data In) signal: + +1. **Open Simulation Settings**: Navigate to the Simulation Settings module +2. **Select GPI Pin**: In "Select R31 (Input) Signals", select the pin configured as SDI Signal +3. **Configure Input Mode**: Choose Timestamp Mode or Pattern Mode +4. **Define Data Pattern**: Enter the bit values the PRU should receive + +**Example - Simulating 0xA5 (10100101) with MODE1:** +``` +Input Mode: Timestamp +Input Cycles: [100, 107, 114, 121, 128, 135, 142, 149] +Input Values: [1, 0, 1, 0, 0, 1, 0, 1] +``` + +**Timing Calculation:** +- CS Setup Time determines when the first clock edge occurs +- For SCLK high=7, low=7: each bit period = 14 cycles +- MODE1 samples on falling edge: set data before the falling edge +- Align your input transitions with the expected sample points + +**Viewing Results:** +- The simulation waveform shows both SCLK (output) and SDI (input) +- Verify that data transitions align with the correct clock edges +- Check the received data register value in the **PRU register allocation summary** view under **SIMULATION RESULTS** + +--- + +### How to Verify Simulation Results + +After running simulation: + +1. Open the **PRU register allocation summary** view +2. Look for the **SIMULATION RESULTS** section at the bottom +3. Find your SPI Read block and verify the simulated value + +--- + +### Tips for Creating Custom Patterns + +1. **Always observe your actual waveform first**: Your actual SCLK timing depends on: +- Where the SPI Read block is placed in your flow +- Blocks executed before it (they consume cycles) +- Your specific timing configuration + +2. **Start with all 1s or all 0s**: Set `Input Cycles: [1]`, `Input Values: [1]` or `[0]` with Repeat Last Bit enabled to verify you can receive constant data + +3. **Identify exact sample points from waveform**: +- Run simulation with the above constant pattern +- Look at the SCLK waveform to see when clock edges occur +- Note the cycle numbers of the sampling edges for your mode: + - MODE0: Rising edges + - MODE1: Falling edges + - MODE2: Falling edges + - MODE3: Rising edges + +4. **Set SDI transitions BEFORE sample points**: Once you know when sampling occurs (e.g., cycles 50, 60, 70...), set your SDI transitions a few cycles earlier (e.g., cycles 48, 58, 68...) + +5. **Use the mode's sampling edge**: +- MODE0/MODE2: Sample on the first clock edge after the idle state changes +- MODE1/MODE3: Sample on the second clock edge + +6. **Verify incrementally**: If the full byte isn't working, test one bit at a time to identify timing issues + +### Terminology +- **SPI**: Serial Peripheral Interface - synchronous serial protocol +- **Bit-banging**: Software-controlled pin toggling to implement protocols +- **SCLK**: Serial Clock - timing signal for synchronization +- **SDI**: Serial Data In - data from peripheral to controller +- **CS**: Chip Select - enables/disables peripheral device +- **MSB/LSB**: Most/Least Significant Bit - bit order +- **Endianness**: Order of bit/byte transmission +- **CPOL**: Clock Polarity - idle state of clock (0=LOW, 1=HIGH) +- **CPHA**: Clock Phase - which edge shifts data (0=first edge, 1=second edge) +- **Setup Time**: Minimum time data must be stable before clock edge +- **Hold Time**: Minimum time data must remain stable after clock edge +- **CS Setup Time**: Time between CS assertion and first clock edge +- **CS Hold Time**: Time between last clock edge and CS deassertion + +--- +## How to Configure (For AI/Scripting) + +This section describes how to programmatically configure the SPI Read block in a .syscfg file. + +### Adding a SPI Read Instance + +\`\`\`javascript +const pru_spi_read = scripting.addModule("/pru_blocks/pru_io_blocks/pru_spi_read", {}, false); +const spi_read1 = pru_spi_read.addInstance(); +\`\`\` + +### Configuration Parameters + +| Parameter | Type | Valid Values | Default | Description | +|-----------|------|--------------|---------|-------------| +| Device Mode | String | "controller", "peripheral" | "controller" | SPI role selection | +| SPI Mode | String | "MODE0", "MODE1", "MODE2", "MODE3" | "MODE1" | Clock polarity and phase | +| packetSize | Integer | 8-32 | 8 | Number of bits to read | +| Endiness | String | "most significant bit first", "least significant bit first" | "least significant bit first" | Bit order | +| SCLK Signal | String | "0"-"19" | "0" | GPIO pin for clock | +| SDI Signal | String | "0"-"19" | "1" | GPIO pin for data input | +| CS Signal | String | "0"-"19" | "2" | GPIO pin for chip select | +| sclk high pulse width (in PRU cycles) | Integer | 1-0xFFFFFFFF | 7 | Clock high time (Controller only) | +| sclk low pulse width (in PRU cycles) | Integer | 1-0xFFFFFFFF | 7 | Clock low time (Controller only) | +| CS Setup Time | Integer | 0-10000 | 35 | CS setup time in nanoseconds (Controller only) | +| CS Hold Time | Integer | 0-10000 | 10 | CS hold time in nanoseconds (Controller only) | +| Data Setup Time | Integer | 0-10000 | 0 | Data setup time in nanoseconds, converted to PRU cycles internally (Controller only) | +| CS Filter Cycles | Integer | 1-0xFFFFFFFF | 2 | CS glitch filter cycles (Peripheral only) | + +### Example Configurations + +**SPI Controller Read, MODE1, 8-bit, LSB first:** +\`\`\`javascript +spi_read1.$name = "SPI_Read_0"; +spi_read1["Device Mode"] = "controller"; +spi_read1["SPI Mode"] = "MODE1"; +spi_read1.packetSize = 8; +spi_read1["Endiness"] = "least significant bit first"; +spi_read1["SCLK Signal"] = "0"; +spi_read1["SDI Signal"] = "1"; +spi_read1["CS Signal"] = "2"; +spi_read1["sclk high pulse width (in PRU cycles)"] = 7; +spi_read1["sclk low pulse width (in PRU cycles)"] = 7; +spi_read1["CS Setup Time"] = 35; +spi_read1["CS Hold Time"] = 10; +\`\`\` + +**SPI Peripheral Read, MODE3, 16-bit, MSB first:** +\`\`\`javascript +spi_read1.$name = "SPI_Peripheral_Read"; +spi_read1["Device Mode"] = "peripheral"; +spi_read1["SPI Mode"] = "MODE3"; +spi_read1.packetSize = 16; +spi_read1["Endiness"] = "most significant bit first"; +spi_read1["SCLK Signal"] = "4"; // Input pin for clock +spi_read1["SDI Signal"] = "5"; +spi_read1["CS Signal"] = "6"; // Input pin for CS +spi_read1["CS Filter Cycles"] = 2; +\`\`\` + +### Connecting to Other Blocks + +\`\`\`javascript +// Connect SPI Read output to downstream processing block +scripting.connect(spi_read1, "output1", process_block, "input1"); + +// Connect control flow +scripting.connect(prev_block, "next", spi_read1, "prev"); +scripting.connect(spi_read1, "next", next_block, "prev"); +\`\`\` + +### Important Notes + +1. **Pin Assignment**: In Controller mode, SCLK and CS are outputs (GPO). In Peripheral mode, SCLK and CS are inputs (GPI). SDI is always input (GPI). + +2. **Pin Uniqueness**: All three signals (CS, SCLK, SDI) must use different GPIO pins. + +3. **Minimum Pulse Widths** (Controller mode, per SPI mode): + - MODE0: Min High=4, Min Low=3 + - MODE1: Min High=1, Min Low=6 + - MODE2: Min High=3, Min Low=4 + - MODE3: Min High=6, Min Low=1 + +4. **Read-Only Operation**: This block only reads data from the SPI bus. Use SPI Write or SPI Transfer for sending data. \ No newline at end of file diff --git a/docs_ai/pru_io_blocks/pru_spi_transfer.md b/docs_ai/pru_io_blocks/pru_spi_transfer.md new file mode 100644 index 0000000..49d0bde --- /dev/null +++ b/docs_ai/pru_io_blocks/pru_spi_transfer.md @@ -0,0 +1,254 @@ +## PRU SPI Transfer Block + +### Purpose +Implements full-duplex SPI (Serial Peripheral Interface) transfer operation in both Controller and Peripheral modes using bit-banging on PRU GPIO pins. This block simultaneously sends and receives data in a single transaction. + +### How It Works + +**Controller Mode:** +1. **Connect Input**: Connect data source to input port (data to transmit) +2. **Configure Pins**: Select SCLK (clock output), SDI (data input), SDO (data output), and CS (chip select output) pins +3. **Set Timing**: Configure clock pulse widths, setup/hold times, and packet size +4. **Execute**: Generates bit-banged SPI transfer sequence with concurrent read and write +5. **Output**: Provides received data to the next block + +**Peripheral Mode:** +1. **Connect Input**: Connect data source to input port (data to transmit) +2. **Configure Pins**: Select SCLK (clock input), SDI (data input), SDO (data output), and CS (chip select input) pins +3. **Set Mode**: Configure SPI mode (MODE0-3), packet size, and CS filter cycles +4. **Execute**: Waits for CS assertion and controller clock, then simultaneously reads and writes data +5. **Output**: Provides received data to the next block + +### SPI Protocol +SPI is a synchronous serial communication protocol with: +- **SCLK (Serial Clock)**: Clock signal (Controller generates, Peripheral follows) +- **SDI (Serial Data In)**: Data line from device to PRU +- **SDO (Serial Data Out)**: Data line from PRU to device +- **CS (Chip Select)**: Activates the peripheral device (active low) +- **Modes**: Determines clock polarity (CPOL) and phase (CPHA) + +### Configuration Parameters + +**Device Mode**: Select Controller or Peripheral operation mode + +**SPI Mode**: Select MODE0-3 based on clock polarity and phase +- **MODE0** (CPOL=0, CPHA=0): Clock idles low, data sampled on rising edge, shifted on falling edge +- **MODE1** (CPOL=0, CPHA=1): Clock idles low, data sampled on falling edge, shifted on rising edge +- **MODE2** (CPOL=1, CPHA=0): Clock idles high, data sampled on falling edge, shifted on rising edge +- **MODE3** (CPOL=1, CPHA=1): Clock idles high, data sampled on rising edge, shifted on falling edge + +**Packet Size**: Number of bits to transfer (8-32) +- 8 bits = 1 byte (most common) +- 16 bits = 2 bytes +- 32 bits = 4 bytes (maximum) + +**Endianness**: Bit order +- **Most significant bit first** (MSB): Standard SPI, bit 7 → bit 0 +- **Least significant bit first** (LSB): Bit 0 → bit 7 + +**CS Signal**: Select PRU_GPO (Controller) or PRU_GPI (Peripheral) pin for chip select + +**SCLK Signal**: Select PRU_GPO (Controller) or PRU_GPI (Peripheral) pin for clock + +**SDI Signal**: Select PRU_GPI pin for data input (receive from device) + +**SDO Signal**: Select PRU_GPO pin for data output (transmit to device) + +### Clock Timing (Controller Mode Only) +- **SCLK High Width**: PRU cycles clock stays HIGH +- **SCLK Low Width**: PRU cycles clock stays LOW +- **Cycle Period**: Depends on PRU Clock Frequency(should be configured from R5F core and update same frequency in Simulation Settings to use while simulation) +- 200 MHz: 1 cycle = 5ns +- 250 MHz: 1 cycle = 4ns +- 333.333 MHz: 1 cycle = 3ns +- **Example** (at 333.333 MHz): High=13, Low=13 → 26 cycles per bit → ~12.8MHz SPI clock +- **Example** (at 200 MHz): High=13, Low=13 → 26 cycles per bit → ~7.69MHz SPI clock +- The **SPI Clock Frequency** field below automatically calculates the actual frequency based on your configured PRU clock +- Peripheral mode follows controller's clock timing +- **Important**: Timing margins must be sufficient for peripheral response time. Increase pulse widths if data transfer is unreliable. + +### Maximum Achievable Frequency +Different SPI modes have different minimum SCLK width requirements due to timing overhead. +Cycles per bit: **(4+d1) + (6+d2)** + +**Theoretical Maximum (d1=0, d2=0 — controller overhead only):** +- **MODE0**: Min High=4, Min Low=6 → 200 MHz = 20.00 MHz | 333 MHz = 33.30 MHz (Total: 10 cycles) +- **MODE1**: Min High=2, Min Low=6 → 200 MHz = 25.00 MHz | 333 MHz = 41.63 MHz (Total: 8 cycles) +- **MODE2**: Min High=6, Min Low=4 → 200 MHz = 20.00 MHz | 333 MHz = 33.30 MHz (Total: 10 cycles) +- **MODE3**: Min High=6, Min Low=2 → 200 MHz = 25.00 MHz | 333 MHz = 41.63 MHz (Total: 8 cycles) + +**Practical Maximum (d1=9, d2=7 — validated for PRU-to-PRU loopback):** +- All modes: Min High=13, Min Low=13 → **200 MHz = 7.69 MHz** | **333 MHz = 12.80 MHz** + +**Note**: Theoretical maximums assume ideal hardware peripheral response. For full-duplex PRU-to-PRU loopback using the SPI slave macros, use the practical values (d1=9, d2=7) which are validated against the open-pru SPI slave macros. The practical limit exists because the software-polled slave needs ~13 cycles minimum in both the high and low phases to detect edges and process data. Actual maximum frequency depends on peripheral device specifications, signal integrity, and PCB layout. If receiving corrupted data, increase SCLK pulse widths beyond these minimums. + +### Setup and Hold Times (Controller Mode Only) + + +- **CS Setup Time**: Time delay (in nanoseconds) after CS assertion before starting SPI transaction. This ensures the peripheral device is ready before data transfer begins. +- **CS Hold Time**: Time delay (in nanoseconds) after the last bit is transferred before CS deassertion. This ensures the peripheral device has latched the data properly. +- **Data Setup Time**: Minimum time (in nanoseconds) data must be stable before the sampling clock edge. Automatically converted to PRU cycles internally using Math.ceil. + +**Note**: CS Setup Time, CS Hold Time, and Data Setup Time are all specified in **nanoseconds** and automatically converted to PRU cycles based on the PRU Clock Frequency configured in **Simulation Settings**. Ensure the PRU Clock Frequency matches your hardware configuration for accurate timing. + +### Peripheral Mode Parameters +- **CS Filter Cycles**: Number of consecutive cycles CS must be stable to be considered valid. This provides glitch rejection for noisy CS signals. + +### Technical Details (Additional Information) + +**Performance**: +- Cycles per bit ≈ (high_width + low_width + data_setup_time + overhead) +- Total cycles ≈ CS_setup + (packet_size × cycles_per_bit) + CS_hold +- Full-duplex: Same cycles as half-duplex, but transfers both directions simultaneously + +### SPI Communication +**Typical SPI Full-Duplex Transfer**: +1. Controller asserts CS (waits CS Setup Time) +2. Controller outputs data bit on SDO and generates clock edge +3. On the sampling clock edge: +- Peripheral samples controller's data on SDI +- Controller samples peripheral's data on SDI (concurrently) +4. Repeat for all bits in packet +5. Controller waits CS Hold Time, then deasserts CS + +**Key Timing Consideration**: +In full-duplex mode, the peripheral must output its data quickly enough after detecting the shifting clock edge so the controller can sample it on the sampling edge. If timing is too tight, increase SCLK Low Width (MODE1/MODE3) or SCLK High Width (MODE0/MODE2) to give the peripheral more time to respond. + +### Usage Notes +- No hardware SPI - uses GPIO bit-banging for flexibility +- Full-duplex transfers data in both directions simultaneously +- Clock timing directly controls SPI speed +- MODE2 and MODE3 initialize SCLK to HIGH (idle state) before asserting CS +- Setup and hold times should match peripheral device datasheet requirements +- Data input must be connected to this block for transmit data +- Output provides received data for further processing +- Ensure peripheral device supports the configured SPI mode and speed +- Physical pins must be configured via pin mux +- **Timing margins are critical**: If receiving incorrect data, increase SCLK pulse widths to give peripheral more response time + +### Simulating Input Data + +To test SPI Transfer without hardware, use the **Simulation Settings** module to simulate the SDI (Serial Data In) signal: + +1. **Open Simulation Settings**: Navigate to the Simulation Settings module +2. **Select GPI Pin**: In "Select R31 (Input) Signals", select the pin configured as SDI Signal +3. **Configure Input Mode**: Choose Timestamp Mode or Pattern Mode +4. **Define Data Pattern**: Enter the bit values the PRU should receive from the simulated peripheral device + +**Example - Simulating peripheral sending 0xC3 (11000011) with MODE3:** +``` +Input Mode: Timestamp +Input Cycles: [120, 144, 168, 192, 216, 240, 264, 288] +Input Values: [1, 1, 0, 0, 0, 0, 1, 1] +``` + +### Terminology +- **SPI**: Serial Peripheral Interface - synchronous serial protocol +- **Bit-banging**: Software-controlled pin toggling to implement protocols +- **Full-duplex**: Simultaneous bidirectional data transfer +- **SCLK**: Serial Clock - timing signal for synchronization +- **SDI**: Serial Data In - data from peripheral to controller +- **SDO**: Serial Data Out - data from controller to peripheral +- **CS**: Chip Select - enables/disables peripheral device +- **MSB/LSB**: Most/Least Significant Bit - bit order +- **Endianness**: Order of bit/byte transmission +- **CPOL**: Clock Polarity - idle state of clock (0=LOW, 1=HIGH) +- **CPHA**: Clock Phase - which edge shifts data (0=first edge, 1=second edge) +- **Setup Time**: Minimum time data must be stable before clock edge +- **Hold Time**: Minimum time data must remain stable after clock edge +- **CS Setup Time**: Time between CS assertion and first clock edge +- **CS Hold Time**: Time between last clock edge and CS deassertion + +--- + + +## How to Configure (For AI/Scripting) + +This section describes how to programmatically configure the SPI Transfer block in a .syscfg file. + +### Adding a SPI Transfer Instance + +```javascript +const pru_spi_transfer = scripting.addModule("/pru_blocks/pru_io_blocks/pru_spi_transfer", {}, false); +const spi1 = pru_spi_transfer.addInstance(); +``` + +### Configuration Parameters + +| Parameter | Type | Valid Values | Default | Description | +|-----------|------|--------------|---------|-------------| +| Device Mode | String | "controller", "peripheral" | "controller" | SPI role selection | +| SPI Mode | String | "MODE0", "MODE1", "MODE2", "MODE3" | "MODE3" | Clock polarity and phase | +| packetSize | Integer | 8-32 | 32 | Number of bits per transfer | +| Endiness | String | "most significant bit first", "least significant bit first" | "most significant bit first" | Bit order | +| SCLK Signal | String | "0"-"19" | "0" | GPIO pin for clock | +| SDI Signal | String | "0"-"19" | "1" | GPIO pin for data input | +| SDO Signal | String | "0"-"19" | "2" | GPIO pin for data output | +| CS Signal | String | "0"-"19" | "3" | GPIO pin for chip select | +| sclk high pulse width (in PRU cycles) | Integer | 1-0xFFFFFFFF | 9 | Clock high time (Controller only) | +| sclk low pulse width (in PRU cycles) | Integer | 1-0xFFFFFFFF | 7 | Clock low time (Controller only) | +| CS Setup Time | Integer | 0-10000 | 35 | CS setup time in nanoseconds (Controller only) | +| CS Hold Time | Integer | 0-10000 | 10 | CS hold time in nanoseconds (Controller only) | +| Data Setup Time | Integer | 0-10000 | 0 | Data setup time in nanoseconds, converted to PRU cycles internally (Controller only) | +| CS Filter Cycles | Integer | 1-0xFFFFFFFF | 2 | CS glitch filter cycles (Peripheral only) | + +### Example Configurations + +**SPI Controller, MODE3, 8-bit, MSB first:** +```javascript +spi1.$name = "SPI_Controller_0"; +spi1["Device Mode"] = "controller"; +spi1["SPI Mode"] = "MODE3"; +spi1.packetSize = 8; +spi1["Endiness"] = "most significant bit first"; +spi1["SCLK Signal"] = "0"; +spi1["SDI Signal"] = "1"; +spi1["SDO Signal"] = "2"; +spi1["CS Signal"] = "3"; +spi1["sclk high pulse width (in PRU cycles)"] = 13; +spi1["sclk low pulse width (in PRU cycles)"] = 11; +spi1["CS Setup Time"] = 35; +spi1["CS Hold Time"] = 10; +``` + +**SPI Peripheral, MODE0, 32-bit, LSB first:** +```javascript +spi1.$name = "SPI_Peripheral_0"; +spi1["Device Mode"] = "peripheral"; +spi1["SPI Mode"] = "MODE0"; +spi1.packetSize = 32; +spi1["Endiness"] = "least significant bit first"; +spi1["SCLK Signal"] = "4"; // Input pin for clock +spi1["SDI Signal"] = "5"; +spi1["SDO Signal"] = "6"; +spi1["CS Signal"] = "7"; // Input pin for CS +spi1["CS Filter Cycles"] = 2; +``` + +### Connecting to Other Blocks + +```javascript +// Connect data source to SPI input (data to transmit) +scripting.connect(load_constant1, "output1", spi1, "input1"); + +// Connect SPI output to downstream block (received data) +scripting.connect(spi1, "output1", process_block, "input1"); + +// Connect control flow +scripting.connect(prev_block, "next", spi1, "prev"); +scripting.connect(spi1, "next", next_block, "prev"); +``` + +### Important Notes + +1. **Pin Assignment**: In Controller mode, SCLK and CS are outputs (GPO). In Peripheral mode, SCLK and CS are inputs (GPI). + +2. **Pin Uniqueness**: All four signals (CS, SCLK, SDI, SDO) must use different GPIO pins. + +3. **Minimum Pulse Widths** (Controller mode, per SPI mode): + - MODE0: Min High=4, Min Low=6 + - MODE1: Min High=2, Min Low=6 + - MODE2: Min High=6, Min Low=4 + - MODE3: Min High=6, Min Low=2 + +4. **Full-Duplex Operation**: This block simultaneously sends and receives data. Connect both input (transmit data) and use output (receive data) for full-duplex communication. \ No newline at end of file diff --git a/docs_ai/pru_io_blocks/pru_spi_write.md b/docs_ai/pru_io_blocks/pru_spi_write.md new file mode 100644 index 0000000..295cf91 --- /dev/null +++ b/docs_ai/pru_io_blocks/pru_spi_write.md @@ -0,0 +1,243 @@ +## PRU SPI Write Block + +### Purpose +Implements SPI (Serial Peripheral Interface) protocol to write data in both Controller and Peripheral modes using bit-banging on PRU GPIO pins. + +### How It Works + +**Controller Mode:** +1. **Connect Input**: Connect data source to input port +2. **Configure Pins**: Select SCLK (clock output), SDO (data output), and CS (chip select output) pins +3. **Set Timing**: Configure clock pulse widths, setup/hold times, and packet size +4. **Execute**: Generates bit-banged SPI write sequence with proper timing + +**Peripheral Mode:** +1. **Connect Input**: Connect data source to input port +2. **Configure Pins**: Select SCLK (clock input), SDO (data output), and CS (chip select input) pins +3. **Set Mode**: Configure SPI mode (MODE0-3), packet size, and CS filter cycles +4. **Execute**: Waits for CS assertion and controller clock, then writes data + +### SPI Protocol +SPI is a synchronous serial communication protocol with: +- **SCLK (Serial Clock)**: Clock signal (Controller generates, Peripheral follows) +- **SDO (Serial Data Out)**: Data line from PRU to device +- **CS (Chip Select)**: Activates the peripheral device (active low) +- **Modes**: Determines clock polarity (CPOL) and phase (CPHA) + +### Configuration Parameters + +**Device Mode**: Select Controller or Peripheral operation mode + +**SPI Mode**: Select MODE0-3 based on clock polarity and phase +- **MODE0** (CPOL=0, CPHA=0): Clock idles low, data sampled on rising edge, shifted on falling edge +- **MODE1** (CPOL=0, CPHA=1): Clock idles low, data sampled on falling edge, shifted on rising edge +- **MODE2** (CPOL=1, CPHA=0): Clock idles high, data sampled on falling edge, shifted on rising edge +- **MODE3** (CPOL=1, CPHA=1): Clock idles high, data sampled on rising edge, shifted on falling edge + +**Packet Size**: Number of bits to write (8-32) +- 8 bits = 1 byte (most common) +- 16 bits = 2 bytes +- 32 bits = 4 bytes (maximum) + +**Endianness**: Bit order +- **Most significant bit first** (MSB): Standard SPI, bit 7 → bit 0 +- **Least significant bit first** (LSB): Bit 0 → bit 7 + +**CS Signal**: Select PRU_GPO (Controller) or PRU_GPI (Peripheral) pin for chip select + +**SCLK Signal**: Select PRU_GPO (Controller) or PRU_GPI (Peripheral) pin for clock + +**SDO Signal**: Select PRU_GPO pin for data output + +### Clock Timing (Controller Mode Only) +- **SCLK High Width**: PRU cycles clock stays HIGH +- **SCLK Low Width**: PRU cycles clock stays LOW +- **Cycle Period**: Depends on PRU Clock Frequency (should be configured from R5F core and update same frequency in Simulation Settings to use while simulation) +- 200 MHz: 1 cycle = 5ns +- 250 MHz: 1 cycle = 4ns +- 333.333 MHz: 1 cycle = 3ns +- **Example** (at 333.333 MHz): High=7, Low=7 → 14 cycles per bit → ~23.8MHz SPI clock +- **Example** (at 200 MHz): High=7, Low=7 → 14 cycles per bit → ~14.3MHz SPI clock +- The **SPI Clock Frequency** field below automatically calculates the actual frequency based on your configured PRU clock +- Peripheral mode follows controller's clock timing + +### Maximum Achievable Frequency +Different SPI modes have different minimum SCLK width requirements due to timing overhead. +Cycles per bit: **(4+d1) + (3+d2)** + +**Theoretical Maximum (d1=0, d2=0 — controller overhead only):** +- **MODE0**: Min High=2, Min Low=6 → 200 MHz = 25.00 MHz | 333 MHz = 41.63 MHz (Total: 8 cycles) +- **MODE1**: Min High=4, Min Low=3 → 200 MHz = 28.57 MHz | 333 MHz = 47.57 MHz (Total: 7 cycles) +- **MODE2**: Min High=6, Min Low=1 → 200 MHz = 28.57 MHz | 333 MHz = 47.57 MHz (Total: 7 cycles) +- **MODE3**: Min High=3, Min Low=4 → 200 MHz = 28.57 MHz | 333 MHz = 47.57 MHz (Total: 7 cycles) + +**Practical Maximum (d1=0, d2=1 — recommended for reliable operation):** +- All modes: Min High+Low = 8 cycles → **200 MHz = 25.00 MHz** | **333 MHz = 41.63 MHz** + +**Note**: Theoretical maximums assume ideal peripheral response. Practical values (d1=0, d2=1) are recommended for reliable operation and are validated against the open-pru SPI slave macros. Actual maximum frequency depends on peripheral device specifications, signal integrity, and PCB layout. Always verify with oscilloscope and increase pulse widths if data corruption occurs. + +### Setup and Hold Times (Controller Mode Only) + +- **CS Setup Time**: Time delay (in nanoseconds) after CS assertion before starting SPI transaction. This ensures the peripheral device is ready before data transfer begins. +- **CS Hold Time**: Time delay (in nanoseconds) after the last bit is transferred before CS deassertion. This ensures the peripheral device has latched the data properly. +- **Data Setup Time**: Minimum time (in nanoseconds) data must be stable before the sampling clock edge. Automatically converted to PRU cycles internally using Math.ceil. + +**Note**: CS Setup Time, CS Hold Time, and Data Setup Time are all specified in **nanoseconds** and automatically converted to PRU cycles based on the PRU Clock Frequency configured in **Simulation Settings**. Ensure the PRU Clock Frequency matches your hardware configuration for accurate timing. + +### Peripheral Mode Parameters +- **CS Filter Cycles**: Number of consecutive cycles CS must be stable to be considered valid. This provides glitch rejection for noisy CS signals. + +### Technical Details (Additional Information) + +**Performance**: +- Cycles per bit ≈ (high_width + low_width + data_setup_time + overhead) +- Total cycles ≈ CS_setup + (packet_size × cycles_per_bit) + CS_hold + +### SPI Communication +**Typical SPI Transaction**: +1. Controller asserts CS (waits CS Setup Time) +2. Controller outputs data bit on SDO (waits Data Setup Time) +3. Controller generates clock pulse on SCLK +4. Peripheral device samples SDO on clock edge +5. Repeat for all bits in packet +6. Controller waits CS Hold Time, then deasserts CS + +### Usage Notes +- No hardware SPI - uses GPIO bit-banging for flexibility +- Clock timing directly controls SPI speed +- MODE2 and MODE3 initialize SCLK to HIGH (idle state) before asserting CS +- Setup and hold times should match peripheral device datasheet requirements +- Data input must be connected to this block +- Ensure peripheral device supports the configured SPI mode and speed +- Physical pins must be configured via pin mux +- This is a **terminating block** - no output connections + +### Simulation + +The SPI Write block generates output signals (SCLK, SDO, CS) that can be viewed in the simulation waveform: + +1. **Configure Simulation Settings**: Navigate to the Simulation Settings module +2. **Select Output Signals**: In "Select R30 (Output) Signals", select the pins configured for SCLK, SDO, and CS +3. **Set Cycle Count**: Ensure "Number Of PRU Cycles To Simulate" covers your entire SPI transaction +4. **Run Simulation**: View the generated waveforms to verify timing and data output + +**Peripheral Mode Simulation:** +When using Peripheral mode, you need to simulate the controller's SCLK and CS signals: +1. Select the SCLK and CS pins in "Select R31 (Input) Signals" +2. Configure a clock pattern for SCLK using Pattern Mode +3. Configure CS assertion timing using Timestamp Mode +4. The PRU will respond to these simulated inputs by outputting data on SDO + +**Example - Simulating controller clock for Peripheral mode:** +``` +SCLK Pin - Pattern Mode: +Bit Pattern: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1] (7 LOW, 7 HIGH) +Pattern Start Cycle: 100 +Repeat Count: 8 (for 8 bits) + +CS Pin - Timestamp Mode: +Input Cycles: [50, 250] +Input Values: [0, 1] (Assert at cycle 50, deassert at cycle 250) +``` + +### Terminology +- **SPI**: Serial Peripheral Interface - synchronous serial protocol +- **Bit-banging**: Software-controlled pin toggling to implement protocols +- **SCLK**: Serial Clock - timing signal for synchronization +- **SDO**: Serial Data Out - data from controller to peripheral +- **MSB/LSB**: Most/Least Significant Bit - bit order +- **Endianness**: Order of bit/byte transmission +- **CPOL**: Clock Polarity - idle state of clock (0=LOW, 1=HIGH) +- **CPHA**: Clock Phase - which edge shifts data (0=first edge, 1=second edge) +- **Setup Time**: Minimum time data must be stable before clock edge +- **Hold Time**: Minimum time data must remain stable after clock edge +- **CS Setup Time**: Time between CS assertion and first clock edge +- **CS Hold Time**: Time between last clock edge and CS deassertion +--- + +## How to Configure (For AI/Scripting) + +This section describes how to programmatically configure the SPI Write block in a .syscfg file. + +### Adding a SPI Write Instance + +\`\`\`javascript +const pru_spi_write = scripting.addModule("/pru_blocks/pru_io_blocks/pru_spi_write", {}, false); +const spi_write1 = pru_spi_write.addInstance(); +\`\`\` + +### Configuration Parameters + +| Parameter | Type | Valid Values | Default | Description | +|-----------|------|--------------|---------|-------------| +| Device Mode | String | "controller", "peripheral" | "controller" | SPI role selection | +| SPI Mode | String | "MODE0", "MODE1", "MODE2", "MODE3" | "MODE1" | Clock polarity and phase | +| packetSize | Integer | 8-32 | 8 | Number of bits to write | +| Endiness | String | "most significant bit first", "least significant bit first" | "least significant bit first" | Bit order | +| SCLK Signal | String | "0"-"19" | "0" | GPIO pin for clock | +| SDO Signal | String | "0"-"19" | "1" | GPIO pin for data output | +| CS Signal | String | "0"-"19" | "2" | GPIO pin for chip select | +| sclk high pulse width (in PRU cycles) | Integer | 1-0xFFFFFFFF | 7 | Clock high time (Controller only) | +| sclk low pulse width (in PRU cycles) | Integer | 1-0xFFFFFFFF | 7 | Clock low time (Controller only) | +| CS Setup Time | Integer | 0-10000 | 10 | CS setup time in nanoseconds (Controller only) | +| CS Hold Time | Integer | 0-10000 | 10 | CS hold time in nanoseconds (Controller only) | +| Data Setup Time | Integer | 0-10000 | 0 | Data setup time in nanoseconds, converted to PRU cycles internally (Controller only) | +| CS Filter Cycles | Integer | 1-0xFFFFFFFF | 2 | CS glitch filter cycles (Peripheral only) | + +### Example Configurations + +**SPI Controller Write, MODE1, 8-bit, LSB first:** +\`\`\`javascript +spi_write1.$name = "SPI_Write_0"; +spi_write1["Device Mode"] = "controller"; +spi_write1["SPI Mode"] = "MODE1"; +spi_write1.packetSize = 8; +spi_write1["Endiness"] = "least significant bit first"; +spi_write1["SCLK Signal"] = "0"; +spi_write1["SDO Signal"] = "1"; +spi_write1["CS Signal"] = "2"; +spi_write1["sclk high pulse width (in PRU cycles)"] = 7; +spi_write1["sclk low pulse width (in PRU cycles)"] = 7; +spi_write1["CS Setup Time"] = 10; +spi_write1["CS Hold Time"] = 10; +\`\`\` + +**SPI Peripheral Write, MODE0, 32-bit, MSB first:** +\`\`\`javascript +spi_write1.$name = "SPI_Peripheral_Write"; +spi_write1["Device Mode"] = "peripheral"; +spi_write1["SPI Mode"] = "MODE0"; +spi_write1.packetSize = 32; +spi_write1["Endiness"] = "most significant bit first"; +spi_write1["SCLK Signal"] = "4"; // Input pin for clock +spi_write1["SDO Signal"] = "5"; // Output pin for data +spi_write1["CS Signal"] = "6"; // Input pin for CS +spi_write1["CS Filter Cycles"] = 2; +\`\`\` + +### Connecting to Other Blocks + +\`\`\`javascript +// Connect data source to SPI Write input (data to transmit) +scripting.connect(load_constant1, "output1", spi_write1, "input1"); + +// Connect control flow +scripting.connect(prev_block, "next", spi_write1, "prev"); +scripting.connect(spi_write1, "next", next_block, "prev"); +\`\`\` + +### Important Notes + +1. **Pin Assignment**: In Controller mode, SCLK and CS are outputs (GPO). In Peripheral mode, SCLK and CS are inputs (GPI). SDO is always output (GPO). + +2. **Pin Uniqueness**: All three signals (CS, SCLK, SDO) must use different GPIO pins. + +3. **Minimum Pulse Widths** (Controller mode, per SPI mode): + - MODE0: Min High=2, Min Low=6 + - MODE1: Min High=4, Min Low=3 + - MODE2: Min High=6, Min Low=1 + - MODE3: Min High=3, Min Low=4 + +4. **Input Required**: This block requires a data input connection. Connect a Load Constant block or other data source to input1. + +5. **Write-Only Operation**: This block only writes data to the SPI bus. Use SPI Read or SPI Transfer for receiving data. \ No newline at end of file diff --git a/docs_ai/pru_io_blocks/uart_config.md b/docs_ai/pru_io_blocks/uart_config.md new file mode 100644 index 0000000..ba1b3fb --- /dev/null +++ b/docs_ai/pru_io_blocks/uart_config.md @@ -0,0 +1,132 @@ +## UART Config (Combined TX + RX Hardware Configuration) + +### Purpose +Configures the PRU-ICSS ENDAT peripheral for UART TX, RX, or both. Run this block +**once at init**. A single Global Reinit covers both TX and RX setup. + +Use the **UART TX Op** block (`uart_tx_op`) for per-transmission operations and the +**UART RX Op** block (`uart_rx_op`) for per-reception operations. + +### Generated Sequence +1. Global Reinit (`r31` bit 19) FIRST — flushes FIFO and state machines (TRM-mandated order) +2. Poll busy bit — deterministic wait for reinit completion +3. De-assert `rx_en` AFTER reinit — handles stuck `rx_en` from a previous run +4. GPCFG write — enable peripheral interface mode (once, shared by TX and RX) +5. *(if TX enabled)* TXCFG write, TX `CH_CFG0` write, `r30.w2` channel select + `clk_mode=1` +6. *(if RX enabled)* RXCFG write, RX `CH_CFG0` write + +### Important Constraints +- At least one of **Enable TX Config** or **Enable RX Config** must be enabled. +- Only one instance per design (`maxInstances: 1`). +- GPCFG is written once regardless of whether TX-only, RX-only, or both are enabled. +- TX and RX can use **different channels** (e.g., TX on CH0, RX on CH2). + +--- + +## How to Configure (For AI / Scripting) + +### Example `.syscfg` File (Reference) + +```javascript +const uart_config = scripting.addModule("/pru_blocks/pru_io_blocks/uart_config", {}, false); +const uart_config1 = uart_config.addInstance(); + +uart_config1.$name = "PRU_UART_CONFIG_0"; +uart_config1.txClockSource = 1; // 200 MHz (CORE_CLK) +uart_config1.txBaudRate = 25; // 25 MHz +uart_config1.txStartBitPolarity = 0; // Low / Space +uart_config1.txStopBitPolarity = 1; // High / Mark +uart_config1.txBitSwap = false; // MSB first +// Note: RX settings also configured in the same instance if RX is enabled +uart_config1.rxChannel = 1; // RX on Channel 1 +uart_config1.rxClockSource = 1; // 200 MHz +uart_config1.rxBaudRate = 25; +uart_config1.rxOversampleSize = 3; // 4x oversample +uart_config1.rxStartBitPolarity = 0; // Falling edge +uart_config1.rxBitSwap = false; // MSB first + +uart_config1.$position = [0, 0]; +``` + +### Step-by-Step Programmatic Setup + +```javascript +const uart_config = scripting.addModule("/pru_blocks/pru_io_blocks/uart_config", {}, false); +const uart_config1 = uart_config.addInstance(); + +// Basic identification +uart_config1.$name = "PRU_UART_CONFIG_0"; + +// ----- TX Config ----- +uart_config1.enableTX = true; +uart_config1.txChannel = 0; // TX on Channel 0 +uart_config1.txClockSource = 0; // 0 = 192 MHz (UART_CLK), 1 = 200 MHz (CORE_CLK) +uart_config1.txBaudRate = 12; // 12 MHz baud rate +uart_config1.txStartBitPolarity = 1; // 1 = Rising / High (Mark) +uart_config1.txStopBitPolarity = 0; // 0 = Low / Space +uart_config1.txBitSwap = true; // true = LSB first (standard UART) + +// ----- RX Config ----- +uart_config1.enableRX = true; +uart_config1.rxChannel = 2; // RX on Channel 2 +uart_config1.rxClockSource = 0; // 192 MHz +uart_config1.rxBaudRate = 12; // 12 MHz +uart_config1.rxOversampleSize = 7; // 7 = 8x oversample (best noise immunity) +uart_config1.rxStartBitPolarity = 1; // 1 = Rising edge +uart_config1.rxBitSwap = true; // true = LSB first +``` + +--- + +## Configuration Parameters + +### Common / System + +| Parameter | Type | Valid Values | Default | Description | +|-----------|------|--------------|---------|-------------| +| `pruSelect` | Integer | `0` (PRU0), `1` (PRU1) | Auto-detected from `system.getScript("/common")` coreName (`icss_g0_pru0` / `icss_g0_pru1`) | Which PRU core this config applies to | + +### TX Config (only active if `enableTX = true`) + +| Parameter | Type | Valid Values | Default | Description | +|-----------|------|--------------|---------|-------------| +| `enableTX` | Boolean | `true` / `false` | `true` | Enable TX peripheral setup | +| `txChannel` | Integer | `0`, `1`, `2` | `0` | ENDAT channel for TX | +| `txClockSource` | Integer | `0` (192 MHz UART_CLK), `1` (200 MHz CORE_CLK) | `0` | Clock source for TX | +| `txBaudRate` | Integer | Any positive value (MHz) | `12` | Desired TX baud rate. Clock (`192` or `200`) must be divisible by this value | +| `txClockDivider` | Read-only | Calculated | Calculated | `(clockSource / baudRate) - 1`. Read-only | +| `txStartBitPolarity` | Integer | `0` (Low/Space), `1` (High/Mark) | `1` | Polarity of TX start bit | +| `txStopBitPolarity` | Integer | `0` (Low/Space), `1` (High/Mark) | `0` | Polarity of TX stop bit | +| `txBitSwap` | Boolean | `true` (LSB first), `false` (MSB first) | `true` | Bit order | +| `txMode` | Read-only | `"Single-shot"` / `"Continuous"` | `"Single-shot"` | Auto-selected based on data bits (`<= 29` bits = single-shot, else continuous) | + +### RX Config (only active if `enableRX = true`) + +| Parameter | Type | Valid Values | Default | Description | +|-----------|------|--------------|---------|-------------| +| `enableRX` | Boolean | `true` / `false` | `true` | Enable RX peripheral setup | +| `rxChannel` | Integer | `0`, `1`, `2` | `2` | ENDAT channel for RX | +| `rxClockSource` | Integer | `0` (192 MHz UART_CLK), `1` (200 MHz CORE_CLK) | `0` | Clock source for RX | +| `rxBaudRate` | Integer | Any positive value (MHz) | `12` | Desired RX baud rate. Clock must be divisible by `(baudRate * oversample)` | +| `rxClockDivider` | Read-only | Calculated | Calculated | `(clockSource / (baudRate * oversample)) - 1` | +| `rxOversampleSize` | Integer | `0` (1x), `1` (2x), `3` (4x), `7` (8x) | `7` (8x) | Samples per bit | +| `rxStartBitPolarity` | Integer | `0` (Falling Edge), `1` (Rising Edge) | `1` | Edge that indicates RX frame start | +| `rxBitSwap` | Boolean | `true` (LSB first), `false` (MSB first) | `true` | Bit order | + +--- + +## Validation Rules + +- At least one of `enableTX` or `enableRX` must be `true`. +- For TX: `clockMHz % txBaudRate` must equal `0`. The divider (`(clock / baud) - 1`) must be in `[0, 65535]`. +- For RX: `clockMHz % (txBaudRate * oversampleMul)` must equal `0`. The divider (`(clock / (baud * oversample)) - 1`) must be in `[0, 65535]`. + +--- + +## Important Design Notes + +1. **Only one UART Config block per project** (`maxInstances: 1`). +2. **Must run before TX Op or RX Op blocks** — the op blocks assume the peripheral is configured. +3. **Global Reinit is mandatory** (TRM order: Global Reinit → Poll busy → GPCFG → CH config). The macro enforces this order. +4. **RX `rxFrameSize`** is set on the `uart_rx_op` instance (not here) — the config block only sets up the peripheral registers. The `rxFrameSize` value is read by `uart_rx_op` via `getConfigInst()` to determine output port size (`32-bit` vs `64-bit`). +5. **TX `dataBits`** is read by `uart_config` from `uart_tx_op` instances (`getTxDataBits()`) — this determines whether the macro generates single-shot (`<= 29` bits) or continuous mode code. diff --git a/docs_ai/pru_io_blocks/uart_rx_op.md b/docs_ai/pru_io_blocks/uart_rx_op.md new file mode 100644 index 0000000..541a492 --- /dev/null +++ b/docs_ai/pru_io_blocks/uart_rx_op.md @@ -0,0 +1,138 @@ +## UART RX Op (Per-Reception Operation) + +### Purpose +Receives one UART frame using the ENDAT peripheral. This block handles only the +per-reception work: assert rx_en, poll and accumulate all frameSize bits, +extract data, de-assert rx_en. **The `UART Config` block (with RX Config enabled) +must appear earlier in the control flow** to set up the peripheral registers before +this block is called. + +### Generated Sequence +1. Assert rx_en for the configured channel (R30[26/25/24] for CH2/CH1/CH0) +2. Loop frameSize times: poll valid flag (R31[26/25/24]), read middle oversample bit from R31 byte, clear flag, accumulate into output register +3. Extract data — shift to align, remove start and stop bits, mask to data width +4. De-assert rx_en (R30.b3 = 0x00) + +### No Peripheral Register Writes +No GPCFG, RXCFG, or CH_CFG0 writes — those are handled once by `UART Config`. +This means the op block is fast and suitable for repeated calls in a loop. + +### Output Port +The output register size depends on the configured RX Frame Size: + +| Frame Size | Data Bits | Output Port Type | Register(s) | +|------------|-----------|------------------|-------------| +| 3–32 bits | 1–30 bits | **32-bit** (output32) | 1 register (Rx) | +| 33–64 bits | 31–62 bits | **64-bit** (output64) | 2 registers (Rx:Rx+1) | + +- **output1** (32-bit mode): received data word in a single dynamically allocated register +- **output1** (64-bit mode): received data in two consecutive registers — lower 32 bits in the allocated register, upper bits in the next register + +### Configuration +All parameters are automatically read from the paired `UART Config` block — no +duplicate settings needed here. Only `RX Frame Size` is set on this block directly, +since it determines the output port type (32-bit vs 64-bit) which the register +allocator needs to know at design time. + +### RX Frame Size +- Total bits per frame = data bits + 2 (start bit + stop bit) +- Standard UART 8-bit: frameSize = 10 +- 16-bit payload: frameSize = 18 +- frameSize > 32 activates extended mode (two output registers, 64-bit output port) + +### Calculation Example +- UART Config: 192 MHz clock, 12 MHz baud, 8x oversample +- RX Clock = 192 / (clockDiv+1) = 192 / 2 = 96 MHz +- Baud Rate = 96 MHz / 8 = 12 MHz ✓ +- frameSize = 18 → 16 data bits → 32-bit output port (fits in one register) + +### Terminology +- **Valid Flag**: R31 status bit set by hardware when an oversampled bit is ready to read +- **Middle Sample**: For 8x oversample the middle sample is bit 4 of the 8-sample window — most noise-immune point +- **Extended Mode**: frameSize ≥ 33 → data bits ≥ 31 → requires two consecutive output registers +- **rx_en**: R30[26:24] — enables reception on the selected channel; asserting it starts the hardware + +--- + +## How to Configure (For AI/Scripting) + +This section describes how to programmatically configure the UART RX Op block in a .syscfg file. + +**CRITICAL**: The UART RX Op block requires a paired `UART Config` block with RX enabled. +The op block reads all RX parameters (channel, baud rate, oversample, bit order, start bit polarity) +from the config block automatically. Only `rxFrameSize` is set on the op block itself. + +### Step 1 — Add and configure a UART Config block (RX enabled) + +```javascript +const uart_config = scripting.addModule("/pru_blocks/pru_io_blocks/uart_config", {}, false); +const uart_config1 = uart_config.addInstance(); +uart_config1.$name = "PRU_UART_CONFIG_0"; +uart_config1.enableTX = false; // TX-only or TX+RX — set as needed +uart_config1.enableRX = true; +uart_config1.rxChannel = 2; // Channel 2 (GPI11 = PERIF2_IN) +uart_config1.rxClockSource = 0; // 192 MHz (UART_CLK) +uart_config1.rxBaudRate = 12; // 12 MHz +uart_config1.rxOversampleSize = 7; // 8x oversample +uart_config1.rxStartBitPolarity = 1; // Rising edge +uart_config1.rxBitSwap = true; // LSB first (standard UART) +``` + +### Step 2 — Add and configure the UART RX Op block + +```javascript +const uart_rx_op = scripting.addModule("/pru_blocks/pru_io_blocks/uart_rx_op", {}, false); +const uart_rx_op1 = uart_rx_op.addInstance(); +uart_rx_op1.$name = "PRU_UART_RX_OP_0"; +uart_rx_op1.rxFrameSize = 18; // 16 data bits + start + stop = 18 +uart_rx_op1.uartConfig = uart_config1; // Link to config block +``` + +### Step 3 — Connect control flow and data + +```javascript +// Control flow: config must run before op +scripting.connect(uart_config1, "next", uart_rx_op1, "prev"); + +// Data: connect op output to downstream block +scripting.connect(uart_rx_op1, "output1", next_block, "input1"); + +// Control flow out of op +scripting.connect(uart_rx_op1, "next", next_block, "prev"); +``` + +### Configuration Parameters + +| Parameter | Type | Valid Values | Default | Description | +|-----------|------|--------------|---------|-------------| +| rxFrameSize | Integer | 3–64 | 10 | Total frame bits (dataBits + 2). Values > 32 use 64-bit output port | + +All other RX parameters (channel, baud rate, oversample, bit order, start bit polarity) are +read from the paired `UART Config` block — do not duplicate them here. + +### Output Port Type by Frame Size + +| rxFrameSize | Data Bits | Output Port | Notes | +|-------------|-----------|-------------|-------| +| 3–32 | 1–30 | 32-bit (output32) | Single register output | +| 33–64 | 31–62 | 64-bit (output64) | Two consecutive registers; downstream block must accept 64-bit input | + +### Common Frame Sizes + +| Protocol | Data Bits | rxFrameSize | +|----------|-----------|-------------| +| Standard UART 8-bit | 8 | 10 | +| UART 16-bit payload | 16 | 18 | +| UART 24-bit payload | 24 | 26 | +| UART 30-bit payload | 30 | 32 | +| UART 31-bit payload (extended) | 31 | 33 | + +### Important Notes + +1. **UART Config must appear before UART RX Op** in the control flow (connect config "next" to op "prev"). + +2. **rxFrameSize > 32 activates extended mode** — output port becomes 64-bit. Downstream blocks must be wired to accept a 64-bit input. + +3. **No peripheral register writes in this block** — only rx_en assert/de-assert and the bit polling loop. All register setup is in `UART Config`. + +4. **uartConfig linkage is mandatory** — always set `uart_rx_op1.uartConfig = uart_config1` or the block will error during validation. \ No newline at end of file diff --git a/docs_ai/pru_io_blocks/uart_tx_op.md b/docs_ai/pru_io_blocks/uart_tx_op.md new file mode 100644 index 0000000..fb69f10 --- /dev/null +++ b/docs_ai/pru_io_blocks/uart_tx_op.md @@ -0,0 +1,147 @@ +## UART TX Op (Per-Transmission Operation) + +### Purpose +Transmits one UART frame using the ENDAT peripheral. This block handles only the +per-transmission work: frame construction, FIFO loading, start trigger, and wait for +TX complete. **The `UART Config` block (with TX Config enabled) must appear earlier in +the control flow** to set up the peripheral registers before this block is called. + +### Generated Sequence +1. Per-command reinit (R31 bit 19) — clears FIFO and state machines (TRM-mandated order: reinit before de-asserting rx_en) +2. Poll reinit busy bit (R31[5/13/21] for CH0/CH1/CH2) +3. De-assert rx_en (R30.b3 = 0x00) +4. Channel select + clk_mode write to R30.w2 +5. Frame construction — insert start bit, shift data bits, insert stop bit (LSB or MSB order) +6. FIFO load — 1–4 bytes for single-shot (dataBits ≤ 29); 4 bytes + continuous polling for dataBits 30–32; 4 bytes + byte 5 polling for dataBits 33–62 +7. Start transmission (R31 bit 18 = tx_channel_go) +8. Wait for TX complete (poll R31[5/13/21] busy bit) + +### No Peripheral Register Writes +No GPCFG, TXCFG, or CH_CFG0 writes — those are handled once by `UART Config`. +This means the op block is suitable for repeated calls in a loop with minimal overhead. + +### Input Port +The input register size depends on the configured Data Bits: + +| Data Bits | Input Port Type | Register(s) | +|-----------|-----------------|-------------| +| 1–32 bits | **32-bit** (input32) | 1 register (Rx) | +| 33–62 bits | **64-bit** (input64) | 2 consecutive registers (Rx:Rx+1) | + +- **input1** (32-bit mode): data word to transmit in a single register +- **input1** (64-bit mode): data in two consecutive registers — lower 32 bits in the allocated register, upper bits in the next register + +### Configuration +All TX parameters (channel, baud rate, bit order, start/stop polarity) are automatically +read from the paired `UART Config` block. Only `Data Bits` is set on this block directly, +since it determines the input port type (32-bit vs 64-bit) which the register allocator +needs to know at design time. + +### Data Bits +- Number of payload bits to transmit (excluding start and stop bits) +- Range: 1–62 +- dataBits ≤ 29: single-shot mode, 1–4 FIFO bytes +- dataBits 30–32: specific-bit mode, 4–5 FIFO bytes +- dataBits 33–62: continuous mode, 5+ FIFO bytes with polling + +### Calculation Example +- UART Config: 192 MHz clock, 12 MHz baud, LSB first, start=1, stop=0 +- Data Bits: 16 → frame = start(1) + 16 data bits + stop(0) = 18 bits → 3 FIFO bytes +- Frame size written to CH_CFG0 by config block: 18 (dataBits + 2) + +### Terminology +- **Per-command Reinit**: Reinit triggered before every TX to clear FIFO and reset state machines +- **FIFO**: 32-bit TX FIFO in the ENDAT peripheral — data bytes pushed via R30[7:0] +- **tx_channel_go**: R31 bit 18 — triggers transmission of the loaded FIFO content +- **Busy bit**: R31[5/13/21] — 1 = last bit still on wire, 0 = TX complete +- **Single-shot**: TX_FRAME_SIZE set in CH_CFG0 — hardware stops after exactly that many bits +- **Continuous mode**: TX_FRAME_SIZE = 0 — hardware transmits until FIFO is empty + +--- + +## How to Configure (For AI/Scripting) + +This section describes how to programmatically configure the UART TX Op block in a .syscfg file. + +**CRITICAL**: The UART TX Op block requires a paired `UART Config` block with TX enabled. +The op block reads all TX parameters (channel, baud rate, bit order, start/stop polarity) +from the config block automatically. Only `Data Bits` is set on the op block itself. + +### Step 1 — Add and configure a UART Config block (TX enabled) + +```javascript +const uart_config = scripting.addModule("/pru_blocks/pru_io_blocks/uart_config", {}, false); +const uart_config1 = uart_config.addInstance(); +uart_config1.$name = "PRU_UART_CONFIG_0"; +uart_config1.enableTX = true; +uart_config1.enableRX = false; // TX-only or TX+RX — set as needed +uart_config1.txChannel = 0; // Channel 0 (GPO0=CLK, GPO1=DOUT, GPO2=OE) +uart_config1.txClockSource = 0; // 192 MHz (UART_CLK) +uart_config1.txBaudRate = 12; // 12 MHz +uart_config1.txStartBitPolarity = 1; // Start bit = 1 (high) +uart_config1.txStopBitPolarity = 0; // Stop bit = 0 (low) +uart_config1.txBitSwap = true; // LSB first (standard UART) +``` + +### Step 2 — Add and configure the UART TX Op block + +```javascript +const uart_tx_op = scripting.addModule("/pru_blocks/pru_io_blocks/uart_tx_op", {}, false); +const uart_tx_op1 = uart_tx_op.addInstance(); +uart_tx_op1.$name = "PRU_UART_TX_OP_0"; +uart_tx_op1.dataBits = 16; // 16 data payload bits +uart_tx_op1.uartConfig = uart_config1; // Link to config block +``` + +### Step 3 — Connect control flow and data + +```javascript +// Control flow: config must run before op +scripting.connect(uart_config1, "next", uart_tx_op1, "prev"); + +// Data: connect upstream data source to op input +scripting.connect(data_source_block, "output1", uart_tx_op1, "input1"); + +// Control flow out of op +scripting.connect(uart_tx_op1, "next", next_block, "prev"); +``` + +### Configuration Parameters + +| Parameter | Type | Valid Values | Default | Description | +|-----------|------|--------------|---------|-------------| +| dataBits | Integer | 1–62 | 8 | Number of data payload bits. Determines input port type (32-bit vs 64-bit) | + +All other TX parameters (channel, baud rate, bit order, start/stop polarity) are +read from the paired `UART Config` block — do not duplicate them here. + +### Input Port Type by Data Bits + +| dataBits | Input Port | Notes | +|----------|------------|-------| +| 1–32 | 32-bit (input32) | Single register input | +| 33–62 | 64-bit (input64) | Two consecutive registers; upstream block must produce 64-bit output | + +### Common Data Bit Configurations + +| Protocol | Data Bits | Frame Bits (dataBits+2) | Mode | +|----------|-----------|------------------------|------| +| Standard UART 8-bit | 8 | 10 | Single-shot | +| 16-bit payload | 16 | 18 | Single-shot | +| 24-bit payload | 24 | 26 | Single-shot | +| 29-bit payload | 29 | 31 | Single-shot (max single-shot) | +| 30-bit payload | 30 | 32 | Specific-bit mode | +| 32-bit payload | 32 | 34 | Specific-bit mode | +| 33-bit payload | 33 | 35 | Continuous mode | + +### Important Notes + +1. **UART Config must appear before UART TX Op** in the control flow (connect config "next" to op "prev"). + +2. **dataBits > 32 activates continuous mode** — input port becomes 64-bit. The upstream data source block must produce a 64-bit output. + +3. **No peripheral register writes in this block** — only per-command reinit, frame construction, FIFO load, and TX trigger. All register setup is in `UART Config`. + +4. **uartConfig linkage is mandatory** — always set `uart_tx_op1.uartConfig = uart_config1` or the block will error during validation. + +5. **All UART TX Op instances must use the same dataBits value** — `UART Config` uses the first instance's dataBits for TX_FRAME_SIZE configuration. Mismatched instances will generate incorrect assembly. \ No newline at end of file diff --git a/docs_ai/utils/access_look_up_table.md b/docs_ai/utils/access_look_up_table.md new file mode 100644 index 0000000..25a0ae7 --- /dev/null +++ b/docs_ai/utils/access_look_up_table.md @@ -0,0 +1,92 @@ +## Access Lookup Table Block + +### Purpose +Reads data from a lookup table stored in PRU Data Memory (DMEM) using an index value. + +### How It Works +1. **Input**: Receives an index value (0 to tableSize-1) from the connected block +2. **Process**: Generates assembly code to read from the selected Lookup Table at that index position +3. **Output**: Sends the retrieved data value to the next block + +### Configuration Steps +1. A Lookup Table block is automatically created and nested below — configure it with your table data +2. If multiple Lookup Table blocks exist, use the "Lookup Table Selected" field to choose which one to read from +3. Connect an index value to the "index" input port +4. The output data size automatically matches the referenced table's data type (byte/ushort/uint) + +### Technical Details (Additional Information) +**Generated Assembly**: +- LDI32 TEMP_REG1, `LUT_BASE_ADDRESS` ; Load table base address (2 cycles) +- LBBO &result, TEMP_REG1, index, size ; Load data from PRU DRAM (3 cycles for ≤4 bytes) + +**Performance**: 5 PRU cycles total (assuming word-aligned access to PRU DRAM) +- LDI32: 2 cycles +- LBBO: 3 cycles (2 + N where N=1 for reading ≤4 bytes) + +Note: Add +1 cycle if index results in non-word-aligned address + +**Terminology**: +- **LBBO**: Load Byte Burst from Offset - reads 1/2/4 bytes from memory +- **DMEM**: PRU Data Memory - 8KB local RAM in each PRU core +- **Index**: Zero-based position in the table (must be less than table size) + +--- +## How to Configure (For AI/Scripting) + +This section describes how to programmatically configure the Access Lookup Table block in a .syscfg file. + +### Adding an Access Lookup Table Instance + +\`\`\`javascript +const access_look_up_table = scripting.addModule("/pru_blocks/utils/access_look_up_table", {}, false); +const access_lut1 = access_look_up_table.addInstance(); +\`\`\` + +### Configuration Parameters + +| Parameter | Type | Valid Values | Default | Description | +|-----------|------|--------------|---------|-------------| +| lutReference | String | Name of a Lookup Table instance | "" | Which Lookup Table to read from | + +### Example Configurations + +**Read from a lookup table:** +\`\`\`javascript +// First create the Lookup Table +const look_up_table = scripting.addModule("/pru_blocks/utils/look_up_table", {}, false); +const lut1 = look_up_table.addInstance(); +lut1.$name = "Sine_Table"; +lut1.tableSize = 256; +lut1.dataType = "ushort"; +lut1.initPattern = "sequential"; + +// Then create Access Lookup Table to read from it +access_lut1.$name = "Read_Sine"; +access_lut1.lutReference = "Sine_Table"; +\`\`\` + +### Connecting to Other Blocks + +\`\`\`javascript +// Connect index source to input (index port) +scripting.connect(load_constant1, "output1", access_lut1, "input1"); + +// Connect output to downstream block +scripting.connect(access_lut1, "output1", uart_tx1, "input1"); + +// Connect control flow +scripting.connect(prev_block, "next", access_lut1, "prev"); +scripting.connect(access_lut1, "next", next_block, "prev"); +\`\`\` + +### Important Notes + +1. **Requires Lookup Table**: A Lookup Table block must exist and be referenced by lutReference. + +2. **Index Input**: Connect a block that provides the index value (0 to tableSize-1) to input1. + +3. **Output Size**: Automatically matches the referenced Lookup Table's dataType (1, 2, or 4 bytes). + +4. **Bounds Checking**: Validation warns if constant index is out of bounds. Runtime bounds checking is not performed. + +5. **Performance**: 5 PRU cycles total (2 for LDI32 + 3 for LBBO). \ No newline at end of file diff --git a/docs_ai/utils/data_splitter.md b/docs_ai/utils/data_splitter.md new file mode 100644 index 0000000..1d34bdd --- /dev/null +++ b/docs_ai/utils/data_splitter.md @@ -0,0 +1,5 @@ +```javascript +function getLongDescription() { ... } (see source file for full definition) +``` + +Source file: utils\data_splitter.syscfg.js \ No newline at end of file diff --git a/docs_ai/utils/delay_block.md b/docs_ai/utils/delay_block.md new file mode 100644 index 0000000..fca6748 --- /dev/null +++ b/docs_ai/utils/delay_block.md @@ -0,0 +1,140 @@ +## Delay Block + +### Purpose +Introduces a precise timing delay in PRU execution. Each delay count equals one PRU clock cycle. + +### How It Works +1. **Set Delay**: Specify the number of PRU clock cycles to wait (1-255) +2. **Execute**: Generates a loop that executes NOP instructions for the specified duration +3. **Continue**: After delay completes, execution proceeds to the next block + +### Configuration +- **PRU Clocks To Wait**: Number of cycles to delay (1-255) +- Each cycle = 5ns at 200MHz PRU clock +- Example: 200 cycles = 1 microsecond delay + +### Timing Calculations +At 200MHz PRU clock (default on most TI devices): +- 1 cycle = 5 nanoseconds +- 200 cycles = 1 microsecond +- 200,000 cycles = 1 millisecond (requires multiple blocks) + +**Examples**: +- 10 cycles = 50ns +- 100 cycles = 500ns +- 255 cycles (max) = 1.275 microseconds + +### Technical Details (Additional Information) +**Generated Assembly**: +- loop endloop, count - 1 ; Setup loop counter (2 cycles overhead) +- NOP ; No operation (count-1 times) +- endloop: ; Loop end label + +**Total Cycles**: count + 2 (2 cycle overhead for loop setup) + +### Usage Notes +- Maximum delay per block: 255 cycles (hardware limitation) +- Minimum delay is 1 cycle (+ 2 overhead = 3 total) +- This is a **pass-through block** - connects input to output without modification + +### For Delays Greater Than 255 Cycles + +Since the Delay block is limited to 255 cycles maximum, use the **Loop block** for longer delays: + +**Method 1: Loop with single Delay block** + +Loop (count: N) → Delay (255 cycles) + +Total delay = N × 255 cycles +Example: Loop count 10 with Delay 255 = 2,550 cycles = 12.75μs @ 200MHz + +**Method 2: Loop with multiple Delay blocks in sequence** + +Loop (count: N) → Delay (255 cycles) → Delay (255 cycles) → Delay (100 cycles) + +Total delay = N × (255 + 255 + 100) = N × 610 cycles +Example: Loop count 100 with 610 cycles = 61,000 cycles = 305μs @ 200MHz + +**Method 3: Nested loops for very long delays** + +Outer Loop (count: 1000) +└─ Inner Loop (count: 200) + └─ Delay (255 cycles) + +Total delay = 1000 × 200 × 255 = 51,000,000 cycles = 255ms @ 200MHz + +**Delay Examples**: +- **10 microseconds**: Loop(40) → Delay(50) = 2,000 cycles +- **100 microseconds**: Loop(100) → Delay(200) = 20,000 cycles +- **1 millisecond**: Loop(200) → Loop(5) → Delay(200) = 200,000 cycles +- **10 milliseconds**: Loop(1000) → Loop(10) → Delay(200) = 2,000,000 cycles + +**Important Notes**: +- Loop overhead adds 2-3 cycles per iteration +- For precise timing, account for loop setup overhead +- Inner loop body executes sequentially (prev to next connections) +- Use simulation to verify exact cycle counts + +### Terminology +- **PRU Clock**: The clock signal driving PRU execution (typically 200MHz) +- **Cycle**: One tick of the PRU clock +- **NOP**: No Operation - instruction that does nothing but consume time +- **Loop overhead**: Extra cycles required for loop setup/teardown +- **Nested loops**: Loop block inside another Loop block for longer delays + +--- + +## How to Configure (For AI/Scripting) + +This section describes how to programmatically configure the Delay block in a .syscfg file. + +### Adding a Delay Instance + +\`\`\`javascript +const delay_block = scripting.addModule("/pru_blocks/utils/delay_block", {}, false); +const delay1 = delay_block.addInstance(); +\`\`\` + +### Configuration Parameters + +| Parameter | Type | Valid Values | Default | Description | +|-----------|------|--------------|---------|-------------| +| delayCount | Integer | 1-255 | 1 | Number of PRU clock cycles to wait | + +### Example Configurations + +**Short delay (50ns at 200MHz):** +\`\`\`javascript +delay1.$name = "Delay_Short"; +delay1.delayCount = 10; // 10 cycles = 50ns +\`\`\` + +**Medium delay (500ns at 200MHz):** +\`\`\`javascript +delay1.$name = "Delay_Medium"; +delay1.delayCount = 100; // 100 cycles = 500ns +\`\`\` + +**Maximum single-block delay (1.275us at 200MHz):** +\`\`\`javascript +delay1.$name = "Delay_Max"; +delay1.delayCount = 255; // 255 cycles = 1.275us +\`\`\` + +### Connecting to Other Blocks + +\`\`\`javascript +// Connect control flow (Delay is a pass-through block) +scripting.connect(prev_block, "next", delay1, "prev"); +scripting.connect(delay1, "next", next_block, "prev"); +\`\`\` + +### Important Notes + +1. **Maximum Delay**: Single Delay block limited to 255 cycles. Use Loop block for longer delays. + +2. **Timing**: At 200MHz PRU clock, 1 cycle = 5ns. delayCount of 200 = 1 microsecond. + +3. **Pass-through**: Delay block has no data ports - it only introduces timing delay in the control flow. + +4. **Single Cycle Special Case**: When delayCount=1, generates single NOP instruction instead of loop. \ No newline at end of file diff --git a/docs_ai/utils/label.md b/docs_ai/utils/label.md new file mode 100644 index 0000000..fa4675d --- /dev/null +++ b/docs_ai/utils/label.md @@ -0,0 +1,44 @@ +```javascript +function getAIContext() { +return getLongDescription() + ` + +## How to Configure (For AI/Scripting) + +This section describes how to programmatically configure the Label block in a .syscfg file. + +### Adding a Label Instance + +\\\`\\\`\\\`javascript +const label_block = scripting.addModule("/pru_blocks/utils/label", {}, false); +const label1 = label_block.addInstance(); +\\\`\\\`\\\` + +### Configuration Parameters + +| Parameter | Type | Valid Values | Default | Description | +|-----------|------|--------------|---------|-------------| +| $name | String | Any valid identifier | "Label_0" | Instance name (displayed as label text) | + +### Example Configuration + +**Add a documentation label:** +\\\`\\\`\\\`javascript +label1.$name = "UART_TX_Section"; +\\\`\\\`\\\` + +### Important Notes + +1. **No Code Generation**: Label blocks are purely for documentation and generate no assembly code. + +2. **No Ports**: Labels have no input/output ports and cannot be connected to other blocks. + +3. **Visual Only**: Labels appear only in the SysConfig GUI and don't affect PRU execution. +`; +} +``` + +```javascript +function getLongDescription() { ... } (see source file for full definition) +``` + +Source file: utils\label.syscfg.js \ No newline at end of file diff --git a/docs_ai/utils/look_up_table.md b/docs_ai/utils/look_up_table.md new file mode 100644 index 0000000..0c0c6b0 --- /dev/null +++ b/docs_ai/utils/look_up_table.md @@ -0,0 +1,5 @@ +```javascript +function getLongDescription() { ... } (see source file for full definition) +``` + +Source file: utils\look_up_table.syscfg.js \ No newline at end of file diff --git a/docs_ai/utils/memory_access_block.md b/docs_ai/utils/memory_access_block.md new file mode 100644 index 0000000..bab45c2 --- /dev/null +++ b/docs_ai/utils/memory_access_block.md @@ -0,0 +1,218 @@ +## Memory Access Block + +### Purpose +Read from or write to PRU memory using symbols defined by Memory Variable blocks. Uses LBBO (Load) or SBBO (Store) instructions with automatic address calculation and bounds checking. + +### How It Works +1. **Select Operation**: Choose Read (LBBO) or Write (SBBO) +2. **Configure Memory Variable**: A Memory Variable block is automatically created and nested below — configure its label name, size, and memory location +3. **Configure Offset**: Set the byte offset from the symbol's base address (0 to buffer size) +4. **Set Data Size**: Choose how many bytes to access (1 to 112 bytes) +5. **Execute**: PRU calculates the absolute address (symbol + offset) and executes LBBO/SBBO instruction + +### Memory Symbol Addressing +The block uses symbols defined by **Memory Variable** blocks: +- A Memory Variable is auto-created and nested under each Memory Access block +- If multiple Memory Variable blocks exist, select which one to access via the dropdown +- Multiple Memory Access blocks can share the same buffer by pointing to the same label name +- The linker automatically resolves the symbol address at link time +- Offset is validated against the buffer size to prevent overflow + +### Generated Assembly + +**Read Operation (LBBO)**: +```assembly +LDI32 R28, (symbol + offset) ; Calculate absolute address +LBBO &R_output, R28, 0, byte_count ; Load data from memory +``` + +**Write Operation (SBBO)**: +```assembly +LDI32 R28, (symbol + offset) ; Calculate absolute address +SBBO &R_input, R28, 0, byte_count ; Store data to memory +``` + +### Configuration Parameters + +#### Operation +- **Read (Load from Memory)**: Uses LBBO instruction, has output port +- **Write (Store to Memory)**: Uses SBBO instruction, has input port for data + +#### Select Memory Symbol +- Choose a symbol from the dropdown of available Memory Variable blocks +- Shows symbol name and size (e.g., "buffer (64 bytes)") +- The linker resolves the symbol address automatically + +#### Offset (bytes) +- Byte offset from the start of the memory symbol +- Range: 0 to (buffer size - data size) +- Validated to ensure offset + data size doesn't exceed buffer bounds +- Example: offset=8 accesses bytes 8-11 (for 4-byte read) + +#### Data Size (bytes) +- Number of bytes to read or write +- Range: 1 to 112 bytes +- For sizes >= 4 bytes, data must be register-aligned +- Default: 4 bytes + +### Technical Details (Additional Information) + +**Performance**: 3 PRU cycles total +- LDI32: 2 cycles (load 32-bit address) +- LBBO/SBBO: 1 cycle (+ memory access latency) + +**Register Usage**: +- Uses TEMP_REG1 (R28) internally for address calculation + +### Usage Examples + +#### Example 1: Read from Memory Reserve buffer +``` +[Memory Variable: rxBuffer, 128 bytes, DMEM] +[Memory Access] → [Process Data] +Config: Operation=Read, Symbol=rxBuffer, Offset=0, Data Size=4 bytes +Result: Reads 4 bytes from rxBuffer[0-3] +``` + +#### Example 2: Write to Shared Memory (PRU to ARM communication) +``` +[Memory Variable: sharedData, 256 bytes, SMEM] +[Data Source] → [Memory Access] +Config: Operation=Write, Symbol=sharedData, Offset=0x10, Data Size=4 bytes +Result: Writes 4 bytes to sharedData[16-19] +``` + +#### Example 3: Array Element Access +``` +[Memory Variable: dataBuffer, 256 bytes, DMEM] +[Memory Access] → [Process] +Config: Operation=Read, Symbol=dataBuffer, Offset=32, Data Size=4 bytes +Result: Reads 4 bytes from dataBuffer[32-35] (8th element in 4-byte array) +``` + +#### Example 4: Store Result to Reserved Memory +``` +[Memory Variable: resultBuffer, 64 bytes, DMEM] +[Calculation] → [Memory Access] +Config: Operation=Write, Symbol=resultBuffer, Offset=0, Data Size=4 bytes +Result: Writes 4 bytes to resultBuffer[0-3] +``` + +#### Example 5: Multi-byte Transfer +``` +[Memory Variable: largeBuffer, 512 bytes, SMEM] +[Data Source] → [Memory Access] +Config: Operation=Write, Symbol=largeBuffer, Offset=0, Data Size=16 bytes +Result: Writes 16 bytes to largeBuffer[0-15] using multiple registers +``` + +### Ports + +**Read Mode**: +- Input: offset (only in Register Input mode) +- Output: data (loaded value) + +**Write Mode**: +- Input 1: data (value to store) +- Input 2: offset (only in Register Input mode) + +### Important Notes + +1. **Symbol Resolution**: The linker resolves the actual memory address at link time. The symbol points to the memory location defined by the Memory Variable block. + +2. **Bounds Checking**: The block validates that offset + data size doesn't exceed the buffer size. If validation fails, an error is shown in SysConfig. + +3. **TEMP_REG1 Usage**: The block uses R28 (TEMP_REG1) internally for address calculation. This register is reserved and should not be used by other blocks during execution. + +4. **Memory Location**: The symbol's memory location (DMEM or SMEM) is determined by the Memory Variable block configuration: +- DMEM (Local): Fast access, 8KB per PRU, private to each core +- SMEM (Shared): Shared between PRUs and ARM, 64KB total, use for inter-core communication + +### Terminology + +- **LBBO**: Load Byte Burst Operation - PRU instruction for direct memory read +- **SBBO**: Store Byte Burst Operation - PRU instruction for direct memory write +- **DMEM**: Data Memory - PRU local RAM +- **Symbol**: Named memory location defined by Memory Variable block +- **.usect**: Assembler directive used by Memory Reserve to allocate memory + +--- + +## How to Configure (For AI/Scripting) + +This section describes how to programmatically configure the Memory Access block in a .syscfg file. + +### Adding a Memory Access Instance + +\`\`\`javascript +const memory_load_block = scripting.addModule("/pru_blocks/data_handling/memory_load_block", {}, false); +const mem_access1 = memory_load_block.addInstance(); +\`\`\` + +### Configuration Parameters + +| Parameter | Type | Valid Values | Default | Description | +|-----------|------|--------------|---------|-------------| +| operationMode | String | "read", "write" | "read" | Read (LBBO) or Write (SBBO) operation | +| symbolSelect | String | Symbol name from Memory Reserve | "" | Symbol name from Memory Variable block dropdown | +| offsetValue | Integer | 0 to (buffer_size - dataSize) | 0 | Byte offset from symbol start, validated against buffer size | +| dataSize | Integer | 1-112 | 4 | Number of bytes to read/write (1-112 bytes, register-aligned for >=4) | + +### Example Configurations + +**Read 4 bytes from beginning of buffer:** +\`\`\`javascript +// First create Memory Variable block +const memory_reserve = scripting.addModule("/pru_blocks/utils/memory_variable_block", {}, false); +const mem_reserve1 = memory_reserve.addInstance(); +mem_reserve1.$name = "Memory_Reserve_0"; +mem_reserve1.labelName = "rxBuffer"; +mem_reserve1.sizeInBytes = 128; +mem_reserve1.memoryLocation = "dmem"; // Local PRU memory + +// Configure Memory Access to read from it +mem_access1.$name = "Memory_Access_Read"; +mem_access1.operationMode = "read"; +mem_access1.symbolSelect = "rxBuffer"; +mem_access1.offsetValue = 0; +mem_access1.dataSize = 4; +\`\`\` + +**Write to shared memory buffer with offset:** +\`\`\`javascript +// First create Memory Variable block in shared memory +const memory_reserve = scripting.addModule("/pru_blocks/utils/memory_variable_block", {}, false); +const mem_reserve1 = memory_reserve.addInstance(); +mem_reserve1.$name = "Memory_Reserve_0"; +mem_reserve1.labelName = "sharedData"; +mem_reserve1.sizeInBytes = 256; +mem_reserve1.memoryLocation = "smem"; // Shared memory for PRU-ARM communication + +// Configure Memory Access to write to offset 0x10 +mem_access1.$name = "Memory_Access_Write"; +mem_access1.operationMode = "write"; +mem_access1.symbolSelect = "sharedData"; +mem_access1.offsetValue = 0x10; // Write to bytes 16-19 +mem_access1.dataSize = 4; +\`\`\` + +### Connecting to Other Blocks + +\`\`\`javascript +// For WRITE mode: connect data source to input1 +scripting.connect(load_constant1, "output1", mem_access1, "input1"); + +// For READ mode: connect output1 to downstream block +scripting.connect(mem_access1, "output1", process_block, "input1"); + +// Connect control flow +scripting.connect(prev_block, "next", mem_access1, "prev"); +\`\`\` + +### Important Notes + +1. **Write Mode Inputs**: When operationMode="write", connect data to input1. If offsetMode="register", also connect offset to input2. + +2. **Read Mode Outputs**: When operationMode="read", the loaded data is available on output1. + +3. **Symbol Addressing**: When using addressingMode="symbol", the symbol must be defined by a Memory Variable block in the same configuration. \ No newline at end of file diff --git a/docs_ai/utils/memory_variable_block.md b/docs_ai/utils/memory_variable_block.md new file mode 100644 index 0000000..97be49c --- /dev/null +++ b/docs_ai/utils/memory_variable_block.md @@ -0,0 +1,190 @@ +## Memory Variable Block + +### Purpose +Reserves uninitialized memory space in a named section using the `.usect` directive. This is useful for declaring buffers, arrays, or any memory that doesn't need initialization at compile time. + +### How It Works +1. **No Runtime Code**: This block only generates a memory reservation directive - no executable code +2. **Uninitialized**: The reserved memory has no initial contents (undefined values at startup) +3. **Named Section**: Memory is placed in a user-specified section (default: .bss) +4. **Linker Placement**: The linker determines the actual memory address based on the linker command file + +### Configuration + +**Label Name** +- The symbol name that points to the first byte of reserved memory +- Must start with a letter or underscore +- Can contain letters, numbers, and underscores +- Example: `my_buffer`, `_data_array`, `rxBuffer1` + +**Size in Bytes** +- Number of bytes to reserve (1 to 8192) +- Example: 256 for a 256-byte buffer + +**Memory Location** +- Choose where to allocate the memory: +- **DMEM (Local)**: Allocated in local PRU Data RAM (8 KB, fast access) +- **SMEM (Shared)**: Allocated in Shared RAM (64 KB, accessible by all PRUs and ARM cores) +- Default: DMEM (Local) + +**Alignment** (Optional) +- Ensures the memory starts on a specific boundary +- Fixed to 4 bytes (word-aligned) for optimal PRU access +- Example: 4 for 4-byte (word) alignment + +### Generated Assembly +```assembly +; Example in DMEM (Local) +myBuffer .usect ".udmem", 256, 4 + +; Example in SMEM (Shared) +sharedData .usect ".usmem", 512, 4 +``` + +### .usect Directive Syntax +``` +symbol .usect "section name", size in bytes[, alignment] +``` + +- **symbol**: Label pointing to first byte of reserved space +- **section name**: Name of uninitialized section (in quotes) +- **size in bytes**: Number of bytes to reserve +- **alignment**: Optional boundary alignment (power of 2) + +### Usage Examples + +**Example 1: Local Buffer in DMEM** +``` +Label: rxBuffer +Size: 128 bytes +Memory Location: DMEM (Local) + +Generated: rxBuffer .usect ".udmem", 128, 4 +``` + +**Example 2: Shared Buffer in SMEM** +``` +Label: sharedData +Size: 512 bytes +Memory Location: SMEM (Shared) + +Generated: sharedData .usect ".usmem", 512, 4 +``` + +**Example 3: Large Shared Buffer** +``` +Label: ipcBuffer +Size: 2048 bytes +Memory Location: SMEM (Shared) + +Generated: ipcBuffer .usect ".usmem", 2048, 4 +``` + +### Accessing Reserved Memory + +To access the reserved memory in your PRU code: +```assembly +; Load address of reserved memory into register +LDI32 R0, myBuffer + +; Write a byte to the buffer +SBBO &R1, R0, 0, 1 + +; Read 4 bytes from offset 8 +LBBO &R2, R0, 8, 4 +``` + +### Differences from Lookup Table Block + +| Feature | Memory Variable | Lookup Table | +|---------|---------------|--------------| +| Initialization | Uninitialized | Initialized with data | +| Directive | .usect | .data section | +| Use Case | Runtime buffers | Pre-computed values | +| Content | Undefined at start | User-defined values | + +### Memory Considerations +- PRU DMEM is 8KB per core - plan your memory usage accordingly +- Multiple Memory Variable blocks can be used for different buffers +- The linker places all .bss sections together unless you use custom sections +- For initialized data, use the Lookup Table block instead + +### Terminology +- **.usect**: Assembler directive to reserve Uninitialized SECTion space +- **.bss**: Block Started by Symbol - standard section for uninitialized data +- **Alignment**: Memory boundary constraint (addresses divisible by alignment value) +- **DMEM**: PRU Data Memory - 8KB local RAM in each PRU core + +--- + +## How to Configure (For AI/Scripting) + +This section describes how to programmatically configure the Memory Variable block in a .syscfg file. + +### Adding a Memory Variable Instance + +\`\`\`javascript +const memory_variable = scripting.addModule("/pru_blocks/utils/memory_variable_block", {}, false); +const mem_variable1 = memory_variable.addInstance(); +\`\`\` + +### Configuration Parameters + +| Parameter | Type | Valid Values | Default | Description | +|-----------|------|--------------|---------|-------------| +| labelName | String | Valid C identifier | "buffer" | Symbol name for the reserved memory | +| sizeInBytes | Integer | 1-8192 | 64 | Number of bytes to reserve | +| memoryLocation | String | "dmem" or "smem" | "dmem" | Memory location (DMEM=local, SMEM=shared) | + +### Example Configurations + +**Local buffer in DMEM:** +\`\`\`javascript +mem_variable1.$name = "Memory_Variable_0"; +mem_variable1.labelName = "rxBuffer"; +mem_variable1.sizeInBytes = 128; +mem_variable1.memoryLocation = "dmem"; +\`\`\` + +**Shared buffer in SMEM:** +\`\`\`javascript +mem_variable1.$name = "Shared_Buffer"; +mem_variable1.labelName = "ipcBuffer"; +mem_variable1.sizeInBytes = 512; +mem_variable1.memoryLocation = "smem"; +\`\`\` + +### Using with Memory Access Block + +\`\`\`javascript +// Create Memory Reserve in DMEM +const memory_variable = scripting.addModule("/pru_blocks/utils/memory_variable_block", {}, false); +const mem_variable1 = memory_variable.addInstance(); +mem_variable1.$name = "Memory_Variable_0"; +mem_variable1.labelName = "my_buffer"; +mem_variable1.sizeInBytes = 64; +mem_variable1.memoryLocation = "dmem"; + +// Create Memory Access that references the symbol +const memory_load_block = scripting.addModule("/pru_blocks/data_handling/memory_load_block", {}, false); +const mem_access1 = memory_load_block.addInstance(); +mem_access1.$name = "Memory_Access_0"; +mem_access1.operationMode = "write"; +mem_access1.addressingMode = "symbol"; +mem_access1.symbolSelect = "my_buffer"; // References the labelName above +mem_access1.dataSize = 4; +\`\`\` + +### Important Notes + +1. **Label Name Rules**: Must start with a letter or underscore, and contain only letters, numbers, and underscores. + +2. **No Runtime Code**: This block only generates a .usect directive - no executable instructions. + +3. **Alignment**: Memory is always 4-byte (word) aligned for optimal PRU access. + +4. **Uninitialized**: Reserved memory has undefined contents at startup. Use Lookup Table block for initialized data. + +5. **Memory Location**: + - **DMEM (Local)**: 8 KB per PRU, fastest access, private to each PRU + - **SMEM (Shared)**: 64 KB total, accessible by all PRUs and ARM cores, use for inter-core communication \ No newline at end of file diff --git a/examples/conditional/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/example.projectspec b/examples/conditional/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/example.projectspec index 5b68f43..160ff49 100644 --- a/examples/conditional/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/example.projectspec +++ b/examples/conditional/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/example.projectspec @@ -12,7 +12,7 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/examples/spi_10mhz/firmware/am261x-lp/icss_m1_pru0_fw/ti-pru-cgt/linker.cmd b/examples/spi_10mhz/firmware/am261x-lp/icss_m1_pru0_fw/ti-pru-cgt/linker.cmd deleted file mode 100644 index 5d7910e..0000000 --- a/examples/spi_10mhz/firmware/am261x-lp/icss_m1_pru0_fw/ti-pru-cgt/linker.cmd +++ /dev/null @@ -1,54 +0,0 @@ -/* - * AM243x_PRU0.cmd - * - * Example Linker command file for linking assembly programs built with the TI-PRU-CGT - * on AM243x PRU0 cores - */ - -/* Specify the System Memory Map */ -MEMORY -{ - PAGE 0: - /* 12 KB PRU Instruction RAM */ - PRU_IMEM : org = 0x00000000 len = 0x00003000 - - PAGE 1: - /* Data RAMs */ - /* 8 KB PRU Data RAM 0; use only the first 4 KB for PRU0 and reserve - * the second 4 KB for RTU0 and Tx_PRU0 */ - PRU0_DMEM_0 : org = 0x00000000 len = 0x00001000 - /* 8 KB PRU Data RAM 1; reserved completely for Slice1 cores - PRU0, - * RTU1 and Tx_PRU0; do not use for any Slice0 cores */ - PRU0_DMEM_1 : org = 0x00002000 len = 0x00001000 - /* NOTE: Custom split of the second 4 KB of ICSS Data RAMs 0 and 1 - * split equally between the corresponding RTU and Tx_PRU cores in - * each slice */ - RTU0_DMEM_0 : org = 0x00001000 len = 0x00000800 - TX_PRU0_DMEM_0 : org = 0x00001800 len = 0x00000800 - RTU1_DMEM_1 : org = 0x00003000 len = 0x00000800 - TX_PRU0_DMEM_1 : org = 0x00003800 len = 0x00000800 - - PAGE 2: - /* C28 needs to be programmed to point to SHAREDMEM, default is 0 */ - /* 64 KB PRU Shared RAM */ - PRU_SHAREDMEM : org = 0x00010000 len = 0x00010000 -} - -/* Specify the sections allocation into memory */ -SECTIONS { - .text:main > 0, PAGE 0 - .text > PRU_IMEM, PAGE 0 - .stack > PRU0_DMEM_0, PAGE 1 - .bss > PRU0_DMEM_0, PAGE 1 - .udmem > PRU0_DMEM_0, PAGE 1 - .initdmem > PRU0_DMEM_0, PAGE 1 - .cio > PRU0_DMEM_0, PAGE 1 - .data > PRU0_DMEM_0, PAGE 1 - .switch > PRU0_DMEM_0, PAGE 1 - .sysmem > PRU0_DMEM_0, PAGE 1 - .cinit > PRU0_DMEM_0, PAGE 1 - .rodata > PRU0_DMEM_0, PAGE 1 - .rofardata > PRU0_DMEM_0, PAGE 1 - .farbss > PRU0_DMEM_0, PAGE 1 - .fardata > PRU0_DMEM_0, PAGE 1 -} diff --git a/examples/spi_10mhz/firmware/am261x-lp/icss_m1_pru0_fw/ti-pru-cgt/makefile b/examples/spi_10mhz/firmware/am261x-lp/icss_m1_pru0_fw/ti-pru-cgt/makefile deleted file mode 100644 index 3be589d..0000000 --- a/examples/spi_10mhz/firmware/am261x-lp/icss_m1_pru0_fw/ti-pru-cgt/makefile +++ /dev/null @@ -1,55 +0,0 @@ -export PRU_NO_CODE_TOOL_PATH?=$(abspath ../../../../../..) -include $(PRU_NO_CODE_TOOL_PATH)/imports.mak - -# Define build outputs -OUTPUT_NAME := spi_10mhz_am261x-lp_icss_m1_pru0_fw - -# MCU+ projects: rename & move hex array output -MCU_HEX_NAME := pru0_load_bin.h -HEX_ARRAY_PREFIX := PRU0Firmware -MCU_HEX_PATH := $(PRU_NO_CODE_TOOL_PATH)/examples/spi_10mhz/firmware/am261x-lp/$(MCU_HEX_NAME) - -# which directories to search for assembly & C source files? -FILES_PATH := .. ../../.. . syscfg/ - -# Linker command file -COMMAND_FILES := linker.cmd - -# Silicon version (3: PRUSS, PRU-ICSS; 4: PRU_ICSSG) -PRU_VERSION := 4 -EXPECTED_DEVICE := am261x - -# Default values are defined in pru_rules.mak: -# - include paths (INCLUDE) -# - compiler flags (CFLAGS) -# - linker flags (LFLAGS) - -# Optional: -# Pre-define here to override default value -# OPT_LEVEL, STACK_SIZE, HEAP_SIZE, or ENTRY_POINT - -# pru_rules.mak has shared settings for all PRU/RTU/TX_PRU core makefiles -include $(PRU_NO_CODE_TOOL_PATH)/pru_rules.mak - -# Optional: -# Append values to INCLUDE, CFLAGS, or LFLAGS here. -# Values can be appended like this: -# INCLUDE += --include_path= - -# Defines (pass instance specific definitions to the program) -# see --define or -D in 'PRU Optimizing C/C++ Compiler User's Guide' -# For example, to define PRU0, ICSSG1, SOC_AM243X, and set _DEBUG_=1: -# -DPRU0 -DICSSG1 --define=SOC_AM243X -D_DEBUG_=1 -DFLAGS := -DPRU0 -DPRU1 --define=SOC_AM261X - -# Libraries -# see --library in 'PRU Optimizing C/C++ Compiler User's Guide' -LIBS := - -syscfg: ../example.syscfg - @echo Generating SysConfig files ... - $(SYSCFG_NODE) $(SYSCFG_CLI_PATH)/dist/cli.js --product $(SYSCFG_PRU_NO_TOOL_PRODUCT) --device AM261x_ZFG --context icss_m1_pru0 --part AM2612 --package ZFG --output syscfg/ ../example.syscfg - -syscfg-gui: - $(SYSCFG_NWJS) $(SYSCFG_PATH) --product $(SYSCFG_PRU_NO_TOOL_PRODUCT) --device AM261x_ZFG --context icss_m1_pru0 --part AM2612 --package ZFG --output syscfg/ ../example.syscfg - diff --git a/examples/spi_10mhz/firmware/am261x-lp/icss_m1_pru0_fw/ti-pru-cgt/makefile_projectspec b/examples/spi_10mhz/firmware/am261x-lp/icss_m1_pru0_fw/ti-pru-cgt/makefile_projectspec deleted file mode 100644 index 5f84611..0000000 --- a/examples/spi_10mhz/firmware/am261x-lp/icss_m1_pru0_fw/ti-pru-cgt/makefile_projectspec +++ /dev/null @@ -1,16 +0,0 @@ -export PRU_NO_CODE_TOOL_PATH?=$(abspath ../../../../../..) -include $(PRU_NO_CODE_TOOL_PATH)/imports.mak - -PROFILE?=Release - -PROJECT_NAME=spi_10mhz_am261x-lp_icss_m1_pru0_fw_ti-pru-cgt - -all: - $(CCS_ECLIPSE) -noSplash -data $(PRU_NO_CODE_TOOL_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectBuild -ccs.projects $(PROJECT_NAME) -ccs.configuration $(PROFILE) - -clean: - $(CCS_ECLIPSE) -noSplash -data $(PRU_NO_CODE_TOOL_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectBuild -ccs.projects $(PROJECT_NAME) -ccs.configuration $(PROFILE) -ccs.clean - -export: - $(MKDIR) $(PRU_NO_CODE_TOOL_PATH)/ccs_projects - $(CCS_ECLIPSE) -noSplash -data $(PRU_NO_CODE_TOOL_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectCreate -ccs.projectSpec example.projectspec -ccs.overwrite full diff --git a/examples/spi_10mhz/firmware/am261x-lp/icss_m1_pru1_fw/example.syscfg b/examples/spi_10mhz/firmware/am261x-lp/icss_m1_pru1_fw/example.syscfg deleted file mode 100644 index b13eaed..0000000 --- a/examples/spi_10mhz/firmware/am261x-lp/icss_m1_pru1_fw/example.syscfg +++ /dev/null @@ -1,49 +0,0 @@ -/** - * These arguments were used when this file was generated. They will be automatically applied on subsequent loads - * via the GUI or CLI. Run CLI with '--help' for additional information on how to override these arguments. - * @cliArgs --device "AM261x_ZFG" --part "AM2612" --package "ZFG" --context "icss_m1_pru1" --product "PRU_NO_CODE_TOOL@01.00.01" - * @v2CliArgs --device "AM2612" --package "NFBGA (ZFG)" --variant "500MHz" --context "icss_m1_pru1" --product "PRU_NO_CODE_TOOL@01.00.01" - * @versions {"tool":"1.27.0+4565"} - */ - -/** - * Import the modules used in this configuration. - */ -const pru_blocks_static_module = scripting.addModule("/pru_blocks/common/pru_blocks_static_module"); -const load_constant_block = scripting.addModule("/pru_blocks/data_handling/load_constant_block", {}, false); -const load_constant_block1 = load_constant_block.addInstance(); -const flow_control_block = scripting.addModule("/pru_blocks/program_control/flow_control_block", {}, false); -const flow_control_block1 = flow_control_block.addInstance(); -const pru_spi_write = scripting.addModule("/pru_blocks/pru_io_blocks/pru_spi_write", {}, false); -const pru_spi_write1 = pru_spi_write.addInstance(); - -/** - * Write custom configuration values to the imported modules. - */ -pru_blocks_static_module.pruClkFreq = 225; - -load_constant_block1.$name = "Load_Constant_0"; -load_constant_block1.constant1 = 3735936685; - -flow_control_block1.$name = "Flow_Control_0"; - -pru_spi_write1.$name = "PRU1_SPI_Write_0"; -pru_spi_write1["Device Mode"] = "peripheral"; -pru_spi_write1["SCLK Signal"] = "4"; -pru_spi_write1["SDO Signal"] = "5"; -pru_spi_write1["CS Signal"] = "6"; -pru_spi_write1.packetSize = 32; -pru_spi_write1.Endiness = "most significant bit first"; - -/** - * Connections between modules. - */ -scripting.connect(load_constant_block1, "output1", pru_spi_write1, "input1"); -scripting.connect(flow_control_block1, "prev", pru_spi_write1, "next"); - -/** - * (x,y) coordinates for modules that are displayed in a graph. - */ -load_constant_block1.$position = [-150,140]; -flow_control_block1.$position = [110,130]; -pru_spi_write1.$position = [-15,130]; diff --git a/examples/spi_10mhz/firmware/am261x-lp/icss_m1_pru1_fw/ti-pru-cgt/example.projectspec b/examples/spi_10mhz/firmware/am261x-lp/icss_m1_pru1_fw/ti-pru-cgt/example.projectspec deleted file mode 100644 index 8d9faa5..0000000 --- a/examples/spi_10mhz/firmware/am261x-lp/icss_m1_pru1_fw/ti-pru-cgt/example.projectspec +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/examples/spi_10mhz/firmware/am261x-lp/icss_m1_pru1_fw/ti-pru-cgt/linker.cmd b/examples/spi_10mhz/firmware/am261x-lp/icss_m1_pru1_fw/ti-pru-cgt/linker.cmd deleted file mode 100644 index 7340f73..0000000 --- a/examples/spi_10mhz/firmware/am261x-lp/icss_m1_pru1_fw/ti-pru-cgt/linker.cmd +++ /dev/null @@ -1,54 +0,0 @@ -/* - * AM243x_PRU1.cmd - * - * Example Linker command file for linking assembly programs built with the TI-PRU-CGT - * on AM243x PRU1 cores - */ - -/* Specify the System Memory Map */ -MEMORY -{ - PAGE 0: - /* 12 KB PRU Instruction RAM */ - PRU_IMEM : org = 0x00000000 len = 0x00003000 - - PAGE 1: - /* Data RAMs */ - /* 8 KB PRU Data RAM 0; use only the first 4 KB for PRU1 and reserve - * the second 4 KB for RTU0 and Tx_PRU1 */ - PRU1_DMEM_0 : org = 0x00000000 len = 0x00001000 - /* 8 KB PRU Data RAM 1; reserved completely for Slice1 cores - PRU1, - * RTU1 and Tx_PRU1; do not use for any Slice0 cores */ - PRU1_DMEM_1 : org = 0x00002000 len = 0x00001000 - /* NOTE: Custom split of the second 4 KB of ICSS Data RAMs 0 and 1 - * split equally between the corresponding RTU and Tx_PRU cores in - * each slice */ - RTU0_DMEM_0 : org = 0x00001000 len = 0x00000800 - TX_PRU1_DMEM_0 : org = 0x00001800 len = 0x00000800 - RTU1_DMEM_1 : org = 0x00003000 len = 0x00000800 - TX_PRU1_DMEM_1 : org = 0x00003800 len = 0x00000800 - - PAGE 2: - /* C28 needs to be programmed to point to SHAREDMEM, default is 0 */ - /* 64 KB PRU Shared RAM */ - PRU_SHAREDMEM : org = 0x00010000 len = 0x00010000 -} - -/* Specify the sections allocation into memory */ -SECTIONS { - .text:main > 0, PAGE 0 - .text > PRU_IMEM, PAGE 0 - .stack > PRU1_DMEM_0, PAGE 1 - .bss > PRU1_DMEM_0, PAGE 1 - .udmem > PRU1_DMEM_0, PAGE 1 - .initdmem > PRU1_DMEM_0, PAGE 1 - .cio > PRU1_DMEM_0, PAGE 1 - .data > PRU1_DMEM_0, PAGE 1 - .switch > PRU1_DMEM_0, PAGE 1 - .sysmem > PRU1_DMEM_0, PAGE 1 - .cinit > PRU1_DMEM_0, PAGE 1 - .rodata > PRU1_DMEM_0, PAGE 1 - .rofardata > PRU1_DMEM_0, PAGE 1 - .farbss > PRU1_DMEM_0, PAGE 1 - .fardata > PRU1_DMEM_0, PAGE 1 -} diff --git a/examples/spi_10mhz/firmware/am261x-lp/icss_m1_pru1_fw/ti-pru-cgt/makefile b/examples/spi_10mhz/firmware/am261x-lp/icss_m1_pru1_fw/ti-pru-cgt/makefile deleted file mode 100644 index 82830f7..0000000 --- a/examples/spi_10mhz/firmware/am261x-lp/icss_m1_pru1_fw/ti-pru-cgt/makefile +++ /dev/null @@ -1,55 +0,0 @@ -export PRU_NO_CODE_TOOL_PATH?=$(abspath ../../../../../..) -include $(PRU_NO_CODE_TOOL_PATH)/imports.mak - -# Define build outputs -OUTPUT_NAME := spi_10mhz_am261x-lp_icss_m1_pru1_fw - -# MCU+ projects: rename & move hex array output -MCU_HEX_NAME := pru1_load_bin.h -HEX_ARRAY_PREFIX := PRU1Firmware -MCU_HEX_PATH := $(PRU_NO_CODE_TOOL_PATH)/examples/spi_10mhz/firmware/am261x-lp/$(MCU_HEX_NAME) - -# which directories to search for assembly & C source files? -FILES_PATH := .. ../../.. . syscfg/ - -# Linker command file -COMMAND_FILES := linker.cmd - -# Silicon version (3: PRUSS, PRU-ICSS; 4: PRU_ICSSG) -PRU_VERSION := 4 -EXPECTED_DEVICE := am261x - -# Default values are defined in pru_rules.mak: -# - include paths (INCLUDE) -# - compiler flags (CFLAGS) -# - linker flags (LFLAGS) - -# Optional: -# Pre-define here to override default value -# OPT_LEVEL, STACK_SIZE, HEAP_SIZE, or ENTRY_POINT - -# pru_rules.mak has shared settings for all PRU/RTU/TX_PRU core makefiles -include $(PRU_NO_CODE_TOOL_PATH)/pru_rules.mak - -# Optional: -# Append values to INCLUDE, CFLAGS, or LFLAGS here. -# Values can be appended like this: -# INCLUDE += --include_path= - -# Defines (pass instance specific definitions to the program) -# see --define or -D in 'PRU Optimizing C/C++ Compiler User's Guide' -# For example, to define PRU1, ICSSG1, SOC_AM243X, and set _DEBUG_=1: -# -DPRU1 -DICSSG1 --define=SOC_AM243X -D_DEBUG_=1 -DFLAGS := -DPRU0 -DPRU1 --define=SOC_AM261X - -# Libraries -# see --library in 'PRU Optimizing C/C++ Compiler User's Guide' -LIBS := - -syscfg: ../example.syscfg - @echo Generating SysConfig files ... - $(SYSCFG_NODE) $(SYSCFG_CLI_PATH)/dist/cli.js --product $(SYSCFG_PRU_NO_TOOL_PRODUCT) --device AM261x_ZFG --context icss_m1_pru1 --part AM2612 --package ZFG --output syscfg/ ../example.syscfg - -syscfg-gui: - $(SYSCFG_NWJS) $(SYSCFG_PATH) --product $(SYSCFG_PRU_NO_TOOL_PRODUCT) --device AM261x_ZFG --context icss_m1_pru1 --part AM2612 --package ZFG --output syscfg/ ../example.syscfg - diff --git a/examples/spi_10mhz/firmware/am261x-lp/icss_m1_pru1_fw/ti-pru-cgt/makefile_projectspec b/examples/spi_10mhz/firmware/am261x-lp/icss_m1_pru1_fw/ti-pru-cgt/makefile_projectspec deleted file mode 100644 index e3c26c0..0000000 --- a/examples/spi_10mhz/firmware/am261x-lp/icss_m1_pru1_fw/ti-pru-cgt/makefile_projectspec +++ /dev/null @@ -1,16 +0,0 @@ -export PRU_NO_CODE_TOOL_PATH?=$(abspath ../../../../../..) -include $(PRU_NO_CODE_TOOL_PATH)/imports.mak - -PROFILE?=Release - -PROJECT_NAME=spi_10mhz_am261x-lp_icss_m1_pru1_fw_ti-pru-cgt - -all: - $(CCS_ECLIPSE) -noSplash -data $(PRU_NO_CODE_TOOL_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectBuild -ccs.projects $(PROJECT_NAME) -ccs.configuration $(PROFILE) - -clean: - $(CCS_ECLIPSE) -noSplash -data $(PRU_NO_CODE_TOOL_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectBuild -ccs.projects $(PROJECT_NAME) -ccs.configuration $(PROFILE) -ccs.clean - -export: - $(MKDIR) $(PRU_NO_CODE_TOOL_PATH)/ccs_projects - $(CCS_ECLIPSE) -noSplash -data $(PRU_NO_CODE_TOOL_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectCreate -ccs.projectSpec example.projectspec -ccs.overwrite full diff --git a/examples/spi_10mhz/firmware/main.asm b/examples/spi_10mhz/firmware/main.asm deleted file mode 100644 index 586984e..0000000 --- a/examples/spi_10mhz/firmware/main.asm +++ /dev/null @@ -1,40 +0,0 @@ -; SPDX-License-Identifier: BSD-3-Clause -; Copyright (C) 2024-2025 Texas Instruments Incorporated - http://www.ti.com/ - -;*************************************************************************************** -; File: main.asm -; -; Brief: Empty example assembly file (asm) with halt instruction -; -; Steps to build : -; -; - Using ccs: -; - Import pru project to ccs workspace -; - main.asm file gets copied to ccs workspace -; - Modify main.asm file -; - Build the pru project, after which .out (Executable output file) and .h (Firmware header) files gets generated -; - Either .out (Executable output file) can be loaded to PRU using ccs or R5F can write to PRU IRAM using PRUICSS driver -; - Using makefile: -; - Use command gmake -all to build PRU project -; -;*************************************************************************************** - -; CCS/makefile specific settings - .retain ; Required for building .out with assembly file - .retainrefs ; Required for building .out with assembly file - - .global main - .ref sysconfig_generated_start - .global sysconfig_generated_end - .sect ".text:main" - -;******** -;* MAIN * -;******** - -main: - ; halt the program after jumping to sysconfig generated start - zero &r0,120 - JMP sysconfig_generated_start -sysconfig_generated_end: - halt diff --git a/examples/spi_10mhz/images/spi_10mhz.png b/examples/spi_10mhz/images/spi_10mhz.png deleted file mode 100644 index cef8f32..0000000 Binary files a/examples/spi_10mhz/images/spi_10mhz.png and /dev/null differ diff --git a/examples/spi_10mhz/makefile b/examples/spi_10mhz/makefile deleted file mode 100644 index 5cd0333..0000000 --- a/examples/spi_10mhz/makefile +++ /dev/null @@ -1,106 +0,0 @@ -include ../../imports.mak - -####################### -# project information # -####################### - -PROJECT_NAME := spi_10mhz -SUPPORTED_PROCESSORS := am261x -# Does the PRU code have dependencies outside of the pru-no-code-tool repo? -PRU_DEPENDENCIES := -# Use NON_PRU_DEPENDENCIES to select which makefiles to call for non-PRU cores -NON_PRU_DEPENDENCIES := mcuplus - -################### -# Prebuild checks # -################### -BUILD_PROJECT := y -DEVICE_NON_PRU := - -# Only build project if $(DEVICE) is in $(SUPPORTED_PROCESSORS) -ifeq (,$(findstring $(DEVICE),$(SUPPORTED_PROCESSORS))) -BUILD_PROJECT := n -MESSAGE := Project $(PROJECT_NAME) does not have a build option for $(DEVICE) -endif - -# Only build project if PRU dependencies exist -ifneq (,$(PRU_DEPENDENCIES)) -# MCU+ SDK dependency? -ifeq (mcuplus,$(findstring mcuplus,$(PRU_DEPENDENCIES))) -ifneq ($(BUILD_MCUPLUS),y) -BUILD_PROJECT := n -MESSAGE ?= Project $(PROJECT_NAME) depends on MCU+ SDK, but BUILD_MCUPLUS != y. -endif -endif -# Additional PRU dependency checks go here. For example: -#ifeq (dependency,$(findstring dependency,$(PRU_DEPENDENCIES))) -#if (dependency check fails) -#BUILD_PROJECT := n -#MESSAGE ?= Project $(PROJECT_NAME) depends on dependency, but dependency does not exist. -#endif -#endif -endif - -# Only build non-PRU code if the non-PRU code is enabled in imports.mak -ifeq ($(BUILD_MCUPLUS),y) -ifeq (mcuplus,$(findstring mcuplus,$(NON_PRU_DEPENDENCIES))) -DEVICE_NON_PRU += $(DEVICE)_mcuplus -endif -endif -ifeq ($(BUILD_LINUX),y) -ifeq (linux,$(findstring linux,$(NON_PRU_DEPENDENCIES))) -DEVICE_NON_PRU += $(DEVICE)_linux -endif -endif - -########################### -# Make and clean commands # -########################### - -ifeq ($(BUILD_PROJECT),y) -# "make" or "make all" builds projects that match $(DEVICE) set in imports.mak -# "make" builds PRU firmware first, then host (non-PRU) code -all: MESSAGE = "Building $(PROJECT_NAME) for $(DEVICE)" -all: pre_build_message - $(MAKE) pru - $(MAKE) host - -# "make pru" builds only PRU firmware for $(DEVICE) -pru: ARGUMENTS_PRU = all -pru: $(DEVICE) - -# "make host" builds only host (non-PRU) code for $(DEVICE) -host: ARGUMENTS_MCUPLUS = all -host: $(DEVICE_NON_PRU) - -# "make clean" cleans projects that match $(DEVICE) set in imports.mak -clean: ARGUMENTS_PRU = clean -clean: ARGUMENTS_MCUPLUS = scrub -clean: MESSAGE = "Cleaning $(PROJECT_NAME) for $(DEVICE)" -clean: pre_build_message $(DEVICE) $(DEVICE_NON_PRU) - -else -# if a prebuild check failed, print message and exit -all clean pru host: pre_build_message -endif - -pre_build_message: - @echo $(MESSAGE) - -###################### -# Target definitions # -###################### - -# provide target definitions for each supported processor -# PRU firmware should be built before any RTOS code that includes it -am261x: -# am261x-lp - $(MAKE) -C firmware/am261x-lp/icss_m1_pru0_fw/ti-pru-cgt $(ARGUMENTS_PRU) - $(MAKE) -C firmware/am261x-lp/icss_m1_pru1_fw/ti-pru-cgt $(ARGUMENTS_PRU) - -am261x_mcuplus: -# am261x-lp - $(MAKE) -C mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang $(ARGUMENTS_MCUPLUS) - -.PHONY: all clean pru host pre_build_message $(DEVICE) $(DEVICE_NON_PRU) $(SUPPORTED_PROCESSORS) - diff --git a/examples/spi_10mhz/mcuplus/am261x-lp/r5fss0-0_freertos/example.syscfg b/examples/spi_10mhz/mcuplus/am261x-lp/r5fss0-0_freertos/example.syscfg deleted file mode 100644 index c9e69a2..0000000 --- a/examples/spi_10mhz/mcuplus/am261x-lp/r5fss0-0_freertos/example.syscfg +++ /dev/null @@ -1,327 +0,0 @@ -/** - * These arguments were used when this file was generated. They will be automatically applied on subsequent loads - * via the GUI or CLI. Run CLI with '--help' for additional information on how to override these arguments. - * @cliArgs --device "AM261x_ZFG" --part "AM2612" --package "ZFG" --context "r5fss0-0" --product "MCU_PLUS_SDK_AM261x@11.00.00" - * @v2CliArgs --device "AM2612" --package "NFBGA (ZFG)" --variant "500MHz" --context "r5fss0-0" --product "MCU_PLUS_SDK_AM261x@11.00.00" - * @versions {"tool":"1.27.0+4565"} - */ - -/** - * Import the modules used in this configuration. - */ -const ioexp = scripting.addModule("/board/ioexp/ioexp", {}, false); -const ioexp1 = ioexp.addInstance(); -const i2c = scripting.addModule("/drivers/i2c/i2c", {}, false); -const i2c1 = i2c.addInstance(); -const pruicss = scripting.addModule("/drivers/pruicss/pruicss", {}, false); -const pruicss1 = pruicss.addInstance(); -const debug_log = scripting.addModule("/kernel/dpl/debug_log"); -const dpl_cfg = scripting.addModule("/kernel/dpl/dpl_cfg"); -const mpu_armv7 = scripting.addModule("/kernel/dpl/mpu_armv7", {}, false); -const mpu_armv71 = mpu_armv7.addInstance(); -const mpu_armv72 = mpu_armv7.addInstance(); -const mpu_armv73 = mpu_armv7.addInstance(); -const mpu_armv74 = mpu_armv7.addInstance(); -const mpu_armv75 = mpu_armv7.addInstance(); -const mpu_armv76 = mpu_armv7.addInstance(); -const default_linker = scripting.addModule("/memory_configurator/default_linker", {}, false); -const default_linker1 = default_linker.addInstance(); -const general = scripting.addModule("/memory_configurator/general", {}, false); -const general1 = general.addInstance(); -const region = scripting.addModule("/memory_configurator/region", {}, false); -const region1 = region.addInstance(); -const section = scripting.addModule("/memory_configurator/section", {}, false); -const section1 = section.addInstance(); -const section2 = section.addInstance(); -const section3 = section.addInstance(); -const section4 = section.addInstance(); -const section5 = section.addInstance(); -const section6 = section.addInstance(); -const section7 = section.addInstance(); -const section8 = section.addInstance(); -const section9 = section.addInstance(); -const section10 = section.addInstance(); -const section11 = section.addInstance(); -const section12 = section.addInstance(); - -/** - * Write custom configuration values to the imported modules. - */ -ioexp1.$name = "CONFIG_IOEXP0"; -ioexp1.TCA6408ARGTR_port0_pinBP_MUX_SW_S1_mode = 0; -ioexp1.TCA6408ARGTR_port0_pinBP_BO_MUX_EN_N_mode = 0; -ioexp1.TCA6408ARGTR_port0_pinBP_MUX_SW_SO_mode = 0; -ioexp1.TCA6408ARGTR_port0_pinBP_MUX_SW_S1_state = 1; -ioexp1.TCA6408ARGTR_port0_pinBP_BO_MUX_EN_mode = 0; - -ioexp1.peripheralDriver = i2c1; -i2c1.$name = "CONFIG_I2C2"; -i2c1.I2C.$assign = "I2C0"; -i2c1.I2C.SCL.$assign = "GPIO135"; -i2c1.I2C.SDA.$assign = "GPIO134"; -i2c1.I2C_child.$name = "drivers_i2c_v1_i2c_v1_template1"; - -pruicss1.$name = "CONFIG_PRU_ICSS0"; -pruicss1.instance = "ICSSM1"; -pruicss1.AdditionalICSSSettings[0].$name = "CONFIG_PRU_ICSS_IO0"; -pruicss1.AdditionalICSSSettings[0].PruGPIO.create(1); -pruicss1.AdditionalICSSSettings[0].PruGPIO[0].$name = "CONFIG_PRU_ICSS_GPIO0"; -pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].$assign = "PRU-ICSS1"; -pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU1_GPIO5.$assign = "GPIO54"; -pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU1_GPIO5.$used = true; -pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU1_GPIO6.rx = true; -pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU1_GPIO6.$assign = "GPIO19"; -pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU1_GPIO6.$used = true; -pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU1_GPIO4.rx = true; -pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU1_GPIO4.$assign = "GPIO15"; -pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU1_GPIO4.$used = true; -pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU0_GPIO0.$assign = "GPIO81"; -pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU0_GPIO0.$used = true; -pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU0_GPIO1.$assign = "GPIO82"; -pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU0_GPIO1.$used = true; -pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU0_GPIO2.$assign = "GPIO83"; -pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU0_GPIO2.$used = true; -pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU0_GPIO9.$assign = "GPIO80"; -pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU1_GPIO11.rx = true; -pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU1_GPIO11.$assign = "GPIO3"; -pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU1_GPIO11.$used = true; -pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU1_GPIO1.$assign = "GPIO72"; -pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU1_GPIO1.$used = true; -pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU1_GPIO2.rx = true; -pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU1_GPIO2.$assign = "GPIO73"; -pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU1_GPIO2.$used = true; -pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU0_GPIO7.$assign = "GPIO26"; -pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU0_GPIO7.$used = true; -pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU0_GPIO6.rx = true; -pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU0_GPIO6.$assign = "GPIO45"; -pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU0_GPIO6.$used = true; - -debug_log.enableUartLog = true; -debug_log.enableSharedMemLog = true; -debug_log.enableSharedMemLogReader = true; -debug_log.uartLog.$name = "CONFIG_UART0"; -debug_log.uartLog.UART.$assign = "UART0"; -debug_log.uartLog.UART.RXD.$assign = "GPIO27"; -debug_log.uartLog.UART.TXD.$assign = "GPIO28"; -debug_log.uartLog.child.$name = "drivers_uart_v2_uart_v2_template0"; - -mpu_armv71.$name = "CONFIG_MPU_REGION0"; -mpu_armv71.size = 31; -mpu_armv71.attributes = "Device"; -mpu_armv71.accessPermissions = "Supervisor RD+WR, User RD"; -mpu_armv71.allowExecute = false; - -mpu_armv72.$name = "CONFIG_MPU_REGION1"; -mpu_armv72.size = 15; -mpu_armv72.accessPermissions = "Supervisor RD+WR, User RD"; - -mpu_armv73.$name = "CONFIG_MPU_REGION2"; -mpu_armv73.baseAddr = 0x80000; -mpu_armv73.size = 15; -mpu_armv73.accessPermissions = "Supervisor RD+WR, User RD"; - -mpu_armv74.$name = "CONFIG_MPU_REGION3"; -mpu_armv74.accessPermissions = "Supervisor RD+WR, User RD"; -mpu_armv74.baseAddr = 0x70000000; -mpu_armv74.size = 21; - -mpu_armv75.$name = "CONFIG_MPU_REGION4"; -mpu_armv75.size = 14; -mpu_armv75.baseAddr = 0x50D00000; -mpu_armv75.allowExecute = false; -mpu_armv75.attributes = "Device"; - -mpu_armv76.$name = "CONFIG_MPU_REGION5"; -mpu_armv76.size = 14; -mpu_armv76.allowExecute = false; -mpu_armv76.attributes = "NonCached"; -mpu_armv76.baseAddr = 0x72000000; - -default_linker1.$name = "memory_configurator_default_linker0"; - -general1.$name = "CONFIG_GENERAL0"; -general1.linker.$name = "TIARMCLANG0"; - -region1.$name = "MEMORY_REGION_CONFIGURATION0"; -region1.memory_region.create(11); -region1.memory_region[0].type = "TCMA"; -region1.memory_region[0].$name = "R5F_VECS"; -region1.memory_region[0].size = 0x40; -region1.memory_region[0].auto = false; -region1.memory_region[1].type = "TCMA"; -region1.memory_region[1].$name = "R5F_TCMA"; -region1.memory_region[1].size = 0x7FC0; -region1.memory_region[2].type = "TCMB"; -region1.memory_region[2].size = 0x8000; -region1.memory_region[2].$name = "R5F_TCMB"; -region1.memory_region[3].$name = "SBL"; -region1.memory_region[3].auto = false; -region1.memory_region[3].size = 0x40000; -region1.memory_region[4].$name = "OCRAM"; -region1.memory_region[4].auto = false; -region1.memory_region[4].manualStartAddress = 0x70040000; -region1.memory_region[4].size = 0x40000; -region1.memory_region[5].type = "FLASH"; -region1.memory_region[5].auto = false; -region1.memory_region[5].manualStartAddress = 0x60100000; -region1.memory_region[5].size = 0x80000; -region1.memory_region[5].$name = "FLASH"; -region1.memory_region[6].$name = "USER_SHM_MEM"; -region1.memory_region[6].auto = false; -region1.memory_region[6].manualStartAddress = 0x70150000; -region1.memory_region[6].size = 0x4000; -region1.memory_region[6].isShared = true; -region1.memory_region[6].shared_cores = ["r5fss0-1"]; -region1.memory_region[7].$name = "LOG_SHM_MEM"; -region1.memory_region[7].auto = false; -region1.memory_region[7].manualStartAddress = 0x70154000; -region1.memory_region[7].size = 0x4000; -region1.memory_region[7].isShared = true; -region1.memory_region[7].shared_cores = ["r5fss0-1"]; -region1.memory_region[8].type = "CUSTOM"; -region1.memory_region[8].$name = "RTOS_NORTOS_IPC_SHM_MEM"; -region1.memory_region[8].auto = false; -region1.memory_region[8].manualStartAddress = 0x72000000; -region1.memory_region[8].size = 0x3E80; -region1.memory_region[8].isShared = true; -region1.memory_region[8].shared_cores = ["r5fss0-1"]; -region1.memory_region[9].type = "CUSTOM"; -region1.memory_region[9].$name = "MAILBOX_HSM"; -region1.memory_region[9].auto = false; -region1.memory_region[9].manualStartAddress = 0x44000000; -region1.memory_region[9].size = 0x3CE; -region1.memory_region[9].isShared = true; -region1.memory_region[9].shared_cores = ["r5fss0-1"]; -region1.memory_region[10].type = "CUSTOM"; -region1.memory_region[10].$name = "MAILBOX_R5F"; -region1.memory_region[10].auto = false; -region1.memory_region[10].manualStartAddress = 0x44000400; -region1.memory_region[10].size = 0x3CE; -region1.memory_region[10].isShared = true; -region1.memory_region[10].shared_cores = ["r5fss0-1"]; - -section1.load_memory = "R5F_VECS"; -section1.group = false; -section1.$name = "Vector Table"; -section1.output_section.create(1); -section1.output_section[0].$name = ".vectors"; -section1.output_section[0].palignment = true; - -section2.load_memory = "OCRAM"; -section2.$name = "Text Segments"; -section2.output_section.create(5); -section2.output_section[0].$name = ".text.hwi"; -section2.output_section[0].palignment = true; -section2.output_section[1].$name = ".text.cache"; -section2.output_section[1].palignment = true; -section2.output_section[2].$name = ".text.mpu"; -section2.output_section[2].palignment = true; -section2.output_section[3].$name = ".text.boot"; -section2.output_section[3].palignment = true; -section2.output_section[4].$name = ".text:abort"; -section2.output_section[4].palignment = true; - -section3.load_memory = "OCRAM"; -section3.$name = "Code and Read-Only Data"; -section3.output_section.create(2); -section3.output_section[0].$name = ".text"; -section3.output_section[0].palignment = true; -section3.output_section[1].$name = ".rodata"; -section3.output_section[1].palignment = true; - -section4.load_memory = "OCRAM"; -section4.$name = "Data Segment"; -section4.output_section.create(1); -section4.output_section[0].$name = ".data"; -section4.output_section[0].palignment = true; - -section5.load_memory = "OCRAM"; -section5.$name = "Memory Segments"; -section5.output_section.create(3); -section5.output_section[0].$name = ".bss"; -section5.output_section[0].output_sections_start = "__BSS_START"; -section5.output_section[0].output_sections_end = "__BSS_END"; -section5.output_section[0].palignment = true; -section5.output_section[1].$name = ".sysmem"; -section5.output_section[1].palignment = true; -section5.output_section[2].$name = ".stack"; -section5.output_section[2].palignment = true; - -section6.load_memory = "OCRAM"; -section6.$name = "Stack Segments"; -section6.output_section.create(5); -section6.output_section[0].$name = ".irqstack"; -section6.output_section[0].output_sections_start = "__IRQ_STACK_START"; -section6.output_section[0].output_sections_end = "__IRQ_STACK_END"; -section6.output_section[0].input_section.create(1); -section6.output_section[0].input_section[0].$name = ". = . + __IRQ_STACK_SIZE;"; -section6.output_section[1].$name = ".fiqstack"; -section6.output_section[1].output_sections_start = "__FIQ_STACK_START"; -section6.output_section[1].output_sections_end = "__FIQ_STACK_END"; -section6.output_section[1].input_section.create(1); -section6.output_section[1].input_section[0].$name = ". = . + __FIQ_STACK_SIZE;"; -section6.output_section[2].$name = ".svcstack"; -section6.output_section[2].output_sections_start = "__SVC_STACK_START"; -section6.output_section[2].output_sections_end = "__SVC_STACK_END"; -section6.output_section[2].input_section.create(1); -section6.output_section[2].input_section[0].$name = ". = . + __SVC_STACK_SIZE;"; -section6.output_section[3].$name = ".abortstack"; -section6.output_section[3].output_sections_start = "__ABORT_STACK_START"; -section6.output_section[3].output_sections_end = "__ABORT_STACK_END"; -section6.output_section[3].input_section.create(1); -section6.output_section[3].input_section[0].$name = ". = . + __ABORT_STACK_SIZE;"; -section6.output_section[4].$name = ".undefinedstack"; -section6.output_section[4].output_sections_start = "__UNDEFINED_STACK_START"; -section6.output_section[4].output_sections_end = "__UNDEFINED_STACK_END"; -section6.output_section[4].input_section.create(1); -section6.output_section[4].input_section[0].$name = ". = . + __UNDEFINED_STACK_SIZE;"; - -section7.load_memory = "OCRAM"; -section7.$name = "Initialization and Exception Handling"; -section7.output_section.create(3); -section7.output_section[0].$name = ".ARM.exidx"; -section7.output_section[0].palignment = true; -section7.output_section[1].$name = ".init_array"; -section7.output_section[1].palignment = true; -section7.output_section[2].$name = ".fini_array"; -section7.output_section[2].palignment = true; - -section8.load_memory = "USER_SHM_MEM"; -section8.type = "NOLOAD"; -section8.$name = "User Shared Memory"; -section8.group = false; -section8.output_section.create(1); -section8.output_section[0].$name = ".bss.user_shared_mem"; -section8.output_section[0].alignment = 0; - -section9.load_memory = "LOG_SHM_MEM"; -section9.$name = "Log Shared Memory"; -section9.group = false; -section9.type = "NOLOAD"; -section9.output_section.create(1); -section9.output_section[0].$name = ".bss.log_shared_mem"; -section9.output_section[0].alignment = 0; - -section10.load_memory = "RTOS_NORTOS_IPC_SHM_MEM"; -section10.type = "NOLOAD"; -section10.$name = "IPC Shared Memory"; -section10.group = false; -section10.output_section.create(1); -section10.output_section[0].$name = ".bss.ipc_vring_mem"; -section10.output_section[0].alignment = 0; - -section11.load_memory = "MAILBOX_HSM"; -section11.type = "NOLOAD"; -section11.$name = "SIPC HSM Queue Memory"; -section11.group = false; -section11.output_section.create(1); -section11.output_section[0].$name = ".bss.sipc_hsm_queue_mem"; -section11.output_section[0].alignment = 0; - -section12.load_memory = "MAILBOX_R5F"; -section12.$name = "SIPC R5F Queue Memory"; -section12.group = false; -section12.type = "NOLOAD"; -section12.output_section.create(1); -section12.output_section[0].$name = ".bss.sipc_secure_host_queue_mem"; -section12.output_section[0].alignment = 0; diff --git a/examples/spi_10mhz/mcuplus/am261x-lp/r5fss0-0_freertos/main.c b/examples/spi_10mhz/mcuplus/am261x-lp/r5fss0-0_freertos/main.c deleted file mode 100644 index b8dd06a..0000000 --- a/examples/spi_10mhz/mcuplus/am261x-lp/r5fss0-0_freertos/main.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2024-2025 Texas Instruments Incorporated - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 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. - * - * Neither the name of Texas Instruments Incorporated 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 - * OWNER 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. - */ - -#include -#include -#include "ti_drivers_config.h" -#include "ti_board_config.h" -#include "FreeRTOS.h" -#include "task.h" - -#define MAIN_TASK_PRI (configMAX_PRIORITIES-1) - -#define MAIN_TASK_SIZE (16384U/sizeof(configSTACK_DEPTH_TYPE)) -StackType_t gMainTaskStack[MAIN_TASK_SIZE] __attribute__((aligned(32))); - -StaticTask_t gMainTaskObj; -TaskHandle_t gMainTask; - -void empty_example_main(void *args); - -void freertos_main(void *args) -{ - empty_example_main(NULL); - - vTaskDelete(NULL); -} - - -int main(void) -{ - /* init SOC specific modules */ - System_init(); - Board_init(); - - /* This task is created at highest priority, it should create more tasks and then delete itself */ - gMainTask = xTaskCreateStatic( freertos_main, /* Pointer to the function that implements the task. */ - "freertos_main", /* Text name for the task. This is to facilitate debugging only. */ - MAIN_TASK_SIZE, /* Stack depth in units of StackType_t typically uint32_t on 32b CPUs */ - NULL, /* We are not using the task parameter. */ - MAIN_TASK_PRI, /* task priority, 0 is lowest priority, configMAX_PRIORITIES-1 is highest */ - gMainTaskStack, /* pointer to stack base */ - &gMainTaskObj ); /* pointer to statically allocated task object memory */ - configASSERT(gMainTask != NULL); - - /* Start the scheduler to start the tasks executing. */ - vTaskStartScheduler(); - - /* The following line should never be reached because vTaskStartScheduler() - will only return if there was not enough FreeRTOS heap memory available to - create the Idle and (if configured) Timer tasks. Heap management, and - techniques for trapping heap exhaustion, are described in the book text. */ - DebugP_assertNoLog(0); - - return 0; -} diff --git a/examples/spi_10mhz/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/example.projectspec b/examples/spi_10mhz/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/example.projectspec deleted file mode 100644 index 9aadbbb..0000000 --- a/examples/spi_10mhz/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/example.projectspec +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/examples/spi_10mhz/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/makefile b/examples/spi_10mhz/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/makefile deleted file mode 100644 index c2f94bd..0000000 --- a/examples/spi_10mhz/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/makefile +++ /dev/null @@ -1,336 +0,0 @@ -# -# Auto generated makefile -# - -export PRU_NO_CODE_TOOL_PATH?=$(abspath ../../../../../..) -include $(PRU_NO_CODE_TOOL_PATH)/imports.mak -include $(MCU_PLUS_SDK_PATH)/devconfig/devconfig.mak - - -CG_TOOL_ROOT=$(CGT_TI_ARM_CLANG_PATH) - -CC=$(CG_TOOL_ROOT)/bin/tiarmclang -LNK=$(CG_TOOL_ROOT)/bin/tiarmclang -STRIP=$(CG_TOOL_ROOT)/bin/tiarmstrip -OBJCOPY=$(CG_TOOL_ROOT)/bin/tiarmobjcopy -COV=$(CG_TOOL_ROOT)/bin/tiarmcov -PROFDATA=$(CG_TOOL_ROOT)/bin/tiarmprofdata -COVERAGE_PATH=$(abspath .) -ifeq ($(OS), Windows_NT) - PYTHON=python -else - PYTHON=python3 -endif - -PROFILE?=release -ConfigName:=$(PROFILE) - -OUTNAME:=spi_10mhz.$(PROFILE).out -COREOUTNAME:=spi_10mhz.$(PROFILE).optishare.out - -BOOTIMAGE_PATH=$(abspath .) -oeconfig?= - -BOOTIMAGE_NAME_MCELF:=spi_10mhz.$(PROFILE).mcelf -BOOTIMAGE_NAME_MCELF_HS:=spi_10mhz.$(PROFILE).mcelf.hs -TARGETS := $(BOOTIMAGE_NAME_MCELF) - -ifeq ($(DEVICE_TYPE), HS) - TARGETS += $(BOOTIMAGE_NAME_MCELF_HS) -endif - - -FILES_common := \ - main.c \ - empty_example.c \ - ti_drivers_config.c \ - ti_drivers_open_close.c \ - ti_board_config.c \ - ti_board_open_close.c \ - ti_dpl_config.c \ - ti_pinmux_config.c \ - ti_power_clock_config.c \ - -FILES_PATH_common = \ - .. \ - ../../.. \ - generated \ - -INCLUDES_common := \ - -I${CG_TOOL_ROOT}/include/c \ - -I${MCU_PLUS_SDK_PATH}/source \ - -I${MCU_PLUS_SDK_PATH}/source/kernel/freertos/FreeRTOS-Kernel/include \ - -I${MCU_PLUS_SDK_PATH}/source/kernel/freertos/portable/TI_ARM_CLANG/ARM_CR5F \ - -I${MCU_PLUS_SDK_PATH}/source/kernel/freertos/config/am261x/r5f \ - -I${MCU_PLUS_SDK_PATH}/source/pru_io/driver \ - -I${PRU_NO_CODE_TOOL_PATH}/examples/spi_10mhz/firmware/am261x-lp \ - -Igenerated \ - -DEFINES_common := \ - -DSOC_AM261X \ - -DOS_FREERTOS \ - -CFLAGS_common := \ - -mcpu=cortex-r5 \ - -mfloat-abi=hard \ - -mfpu=vfpv3-d16 \ - -mthumb \ - -Wall \ - -Werror \ - -g \ - -Wno-gnu-variable-sized-type-not-at-end \ - -Wno-unused-function \ - -CFLAGS_cpp_common := \ - -Wno-c99-designator \ - -Wno-extern-c-compat \ - -Wno-c++11-narrowing \ - -Wno-reorder-init-list \ - -Wno-register \ - -Wno-writable-strings \ - -Wno-enum-compare \ - -Wno-reserved-user-defined-literal \ - -Wno-unused-const-variable \ - -Wno-vla-cxx-extension \ - -x c++ \ - -CFLAGS_debug := \ - -D_DEBUG_=1 \ - -CFLAGS_release := \ - -Os \ - -LNK_FILES_common = \ - generated/linker.cmd \ - -LIBS_PATH_common = \ - -Wl,-i${MCU_PLUS_SDK_PATH}/source/kernel/freertos/lib \ - -Wl,-i${MCU_PLUS_SDK_PATH}/source/drivers/lib \ - -Wl,-i${MCU_PLUS_SDK_PATH}/source/board/lib \ - -Wl,-i${MCU_PLUS_SDK_PATH}/source/pru_io/lib \ - -Wl,-i${CG_TOOL_ROOT}/lib \ - -LIBS_common = \ - -lfreertos.am261x.r5f.ti-arm-clang.${ConfigName}.lib \ - -ldrivers.am261x.r5f.ti-arm-clang.freertos.${ConfigName}.lib \ - -lboard.am261x.r5f.ti-arm-clang.freertos.${ConfigName}.lib \ - -llibc.a \ - -llibsysbm.a \ - -LFLAGS_common = \ - -Wl,--diag_suppress=10063 \ - -Wl,--ram_model \ - -Wl,--reread_libs \ - -Wl,--gen_xml_func_hash \ - - -LIBS_NAME = \ - freertos.am261x.r5f.ti-arm-clang.${ConfigName}.lib \ - drivers.am261x.r5f.ti-arm-clang.freertos.${ConfigName}.lib \ - board.am261x.r5f.ti-arm-clang.freertos.${ConfigName}.lib \ - libc.a \ - libsysbm.a \ - -LIBS_PATH_NAME = \ - ${MCU_PLUS_SDK_PATH}/source/kernel/freertos/lib \ - ${MCU_PLUS_SDK_PATH}/source/drivers/lib \ - ${MCU_PLUS_SDK_PATH}/source/board/lib \ - ${MCU_PLUS_SDK_PATH}/source/pru_io/lib \ - ${CG_TOOL_ROOT}/lib \ - -FILES := $(FILES_common) $(FILES_$(PROFILE)) -ASMFILES := $(ASMFILES_common) $(ASMFILES_$(PROFILE)) -FILES_PATH := $(FILES_PATH_common) $(FILES_PATH_$(PROFILE)) -CFLAGS := $(CFLAGS_common) $(CFLAGS_$(PROFILE)) -ifeq ($(INSTRUMENTATION_MODE), yes) -CFLAGS += -fprofile-instr-generate -fcoverage-mapping -endif -DEFINES := $(DEFINES_common) $(DEFINES_$(PROFILE)) -INCLUDES := $(INCLUDES_common) $(INCLUDE_$(PROFILE)) -LIBS := $(LIBS_common) $(LIBS_$(PROFILE)) -LIBS_PATH := $(LIBS_PATH_common) $(LIBS_PATH_$(PROFILE)) -LFLAGS := $(LFLAGS_common) $(LFLAGS_$(PROFILE)) -LNKOPTFLAGS := $(LNKOPTFLAGS_common) $(LNKOPTFLAGS_$(PROFILE)) -LNK_FILES := $(LNK_FILES_common) $(LNK_FILES_$(PROFILE)) - -OBJDIR := obj/$(PROFILE)/ -OBJS := $(FILES:%.c=%.obj) -OBJS += $(ASMFILES:%.S=%.obj) -DEPS := $(FILES:%.c=%.d) - -vpath %.obj $(OBJDIR) -vpath %.c $(FILES_PATH) -vpath %.S $(FILES_PATH) -vpath %.lib $(LIBS_PATH_NAME) -vpath %.a $(LIBS_PATH_NAME) - -$(OBJDIR)/%.obj %.obj: %.c - @echo Compiling: am261x:r5fss0-0:freertos:ti-arm-clang $(OUTNAME): $< - $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) -MMD -o $(OBJDIR)/$@ $< - -$(OBJDIR)/%.obj %.obj: %.S - @echo Compiling: am261x:r5fss0-0:freertos:ti-arm-clang $(LIBNAME): $< - $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) -o $(OBJDIR)/$@ $< - -all: $(TARGETS) - -SYSCFG_GEN_FILES=generated/ti_drivers_config.c generated/ti_drivers_config.h -SYSCFG_GEN_FILES+=generated/ti_drivers_open_close.c generated/ti_drivers_open_close.h -SYSCFG_GEN_FILES+=generated/ti_dpl_config.c generated/ti_dpl_config.h -SYSCFG_GEN_FILES+=generated/ti_pinmux_config.c generated/ti_power_clock_config.c -SYSCFG_GEN_FILES+=generated/ti_board_config.c generated/ti_board_config.h -SYSCFG_GEN_FILES+=generated/ti_board_open_close.c generated/ti_board_open_close.h - -SYSTEM_FLAG ?= false - -ifeq ($(SYSTEM_FLAG), false) - SYSTEM_COMMAND := syscfg $(SYSCFG_GEN_FILES) $(OBJS) $(LNK_FILES) $(LIBS_NAME) -else - SYSTEM_COMMAND := $(OBJS) $(LNK_FILES) $(LIBS_NAME) -endif - -$(OUTNAME): $(SYSTEM_COMMAND) - @echo . - @echo Linking: am261x:r5fss0-0:freertos:ti-arm-clang $@ ... - $(LNK) $(LNKOPTFLAGS) $(LFLAGS) $(LIBS_PATH) -Wl,-m=$(basename $@).map -o $@ $(addprefix $(OBJDIR), $(OBJS)) $(LIBS) $(LNK_FILES) -Wl,--xml_link_info=$(basename $@).lnkxml - @echo Linking: am261x:r5fss0-0:freertos:ti-arm-clang $@ Done !!! - @echo . - -coreout: $(COREOUTNAME) -$(COREOUTNAME): $(SYSTEM_COMMAND) - @echo . - @echo Relinking Linking: am261x:r5fss0-0:freertos:ti-arm-clang $@ with OptiShare SSO.. - $(LNK) $(LNKOPTFLAGS) $(LFLAGS) $(LIBS_PATH) -Wl,-m=$(basename $@).map -o $@ $(addprefix $(OBJDIR), $(OBJS)) $(LIBS) $(LNK_FILES) -Wl,--xml_link_info=$(basename $@).lnkxml -Wl,--import_sso=$(SSO_PATH) - @echo Relinking with optishare: am261x:r5fss0-0:freertos:ti-arm-clang $@ Done !!! - @echo . - -clean: - @echo Cleaning: am261x:r5fss0-0:freertos:ti-arm-clang $(OUTNAME) ... - $(RMDIR) $(OBJDIR) - $(RM) $(OUTNAME) - $(RM) $(BOOTIMAGE_NAME_MCELF) - $(RM) $(BOOTIMAGE_NAME_MCELF_HS) - $(RMDIR) generated/ - -scrub: - @echo Scrubing: am261x:r5fss0-0:freertos:ti-arm-clang spi_10mhz ... - $(RMDIR) obj -ifeq ($(OS),Windows_NT) - $(RM) \*.out - $(RM) \*.map - $(RM) \*.appimage* - $(RM) \*.rprc* - $(RM) \*.tiimage* - $(RM) \*.bin - $(RM) \*.lnkxml - $(RM) \*.ossr - $(RM) \*.mcelf - $(RM) \*.mcelf_xip - $(RM) \*.mcelf-enc - $(RM) \*.mcelf.hs -else - $(RM) *.out - $(RM) *.map - $(RM) *.appimage* - $(RM) *.rprc* - $(RM) *.tiimage* - $(RM) *.bin - $(RM) *.lnkxml - $(RM) *.ossr - $(RM) *.mcelf - $(RM) *.mcelf_xip - $(RM) *.mcelf-enc - $(RM) *.mcelf.hs -endif - $(RMDIR) generated - -$(OBJS): | $(OBJDIR) - -$(OBJDIR): - $(MKDIR) $@ - - -.NOTPARALLEL: - -.INTERMEDIATE: syscfg -$(SYSCFG_GEN_FILES): syscfg - -ifeq ($(SYSTEM_FLAG), false) -syscfg: ../example.syscfg - @echo Generating SysConfig files ... - $(SYSCFG_NODE) $(SYSCFG_CLI_PATH)/dist/cli.js --product $(SYSCFG_PRU_NO_TOOL_PRODUCT) --product $(SYSCFG_MCU_PLUS_SDK_PRODUCT) --context r5fss0-0 --part ALX --package ALX --output generated/ ../example.syscfg -endif - -syscfg-gui: - $(SYSCFG_NWJS) $(SYSCFG_PATH) --product $(SYSCFG_PRU_NO_TOOL_PRODUCT) --product $(SYSCFG_MCU_PLUS_SDK_PRODUCT) --device AM261x_ALX_beta --context r5fss0-0 --part 2612 --package ZFG --output generated/ ../example.syscfg - -# -# Generation of boot image which can be loaded by Secondary Boot Loader (SBL) -# -ifeq ($(OS),Windows_NT) -EXE_EXT=.exe -endif -ifeq ($(OS),Windows_NT) - BOOTIMAGE_CERT_GEN_CMD=powershell -executionpolicy unrestricted -command $(MCU_PLUS_SDK_PATH)/source/security/security_common/tools/boot/signing/x509CertificateGen.ps1 -else - BOOTIMAGE_CERT_GEN_CMD=$(MCU_PLUS_SDK_PATH)/source/security/security_common/tools/boot/signing/x509CertificateGen.sh -endif -BOOTIMAGE_TEMP_OUT_FILE=temp_stdout_$(PROFILE).txt - -BOOTIMAGE_CERT_KEY=$(APP_SIGNING_KEY) - -BOOTIMAGE_CORE_ID_r5fss0-0 = 0 -BOOTIMAGE_CORE_ID_r5fss0-1 = 1 -BOOTIMAGE_CORE_ID_r5fss1-0 = 2 -BOOTIMAGE_CORE_ID_r5fss1-1 = 3 -SBL_RUN_ADDRESS=0x70002000 -SBL_DEV_ID=55 - -APP_IMAGE_SIGN_CMD = $(MCU_PLUS_SDK_PATH)/source/security/security_common/tools/boot/signing/mcu_appimage_x509_cert_gen.py -MCELF_IMAGE_GEN = $(MCU_PLUS_SDK_PATH)/tools/boot/multicore-elf/genimage.py - -$(BOOTIMAGE_NAME_MCELF): $(OUTNAME) - @echo Boot MulticoreELF image: $(BOOTIMAGE_PATH)/$(BOOTIMAGE_NAME_MCELF) ... - $(PYTHON) $(MCELF_IMAGE_GEN) --core-img=$(BOOTIMAGE_CORE_ID_r5fss0-0):$(OUTNAME) --output=$(BOOTIMAGE_NAME_MCELF) --merge-segments=$(MCELF_MERGE_SEGMENTS_FLAG) --tolerance-limit=$(MCELF_MERGE_SEGMENTS_TOLERANCE_LIMIT) --ignore-context=$(MCELF_IGNORE_CONTEXT_FLAG) --xip=$(MCELF_XIP_RANGE) --xlat=$(MCELF_ADDR_TRANSLATION_PATH) --max-segment-size=$(MCELF_MAX_SEGMENT_SIZE) $(if $(oeconfig),--otfaConfigFile=$(oeconfig)) - @echo Boot MulticoreELF image: $(BOOTIMAGE_PATH)/$(BOOTIMAGE_NAME_MCELF) Done !!! - @echo . - -$(BOOTIMAGE_NAME_MCELF_HS): $(BOOTIMAGE_NAME_MCELF) -ifeq ($(DEVICE_TYPE), HS) -# Sign the appimage using appimage signing script -ifeq ($(ENC_ENABLED),no) -ifeq ($(RSASSAPSS_ENABLED),no) - @echo Boot image signing: Encryption is disabled. - $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME_MCELF) --key $(APP_SIGNING_KEY) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --output $(BOOTIMAGE_NAME_MCELF_HS) -else - @echo Boot image signing: Encryption is disabled. RSASSAPSS is enabled. - $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME_MCELF) --key $(APP_SIGNING_KEY) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --pss_saltlen $(APP_SIGNING_SALT_LENGTH) --output $(BOOTIMAGE_NAME_MCELF_HS) --rsassa_pss -endif -else -ifeq ($(RSASSAPSS_ENABLED),no) - @echo Boot image signing: Encryption is enabled. - $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME_MCELF) --key $(APP_SIGNING_KEY) --enc y --enckey $(APP_ENCRYPTION_KEY) --kd-salt $(KD_SALT) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --enc_key_id $(APP_ENCRYPTION_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --output $(BOOTIMAGE_NAME_MCELF_HS) - $(RM) $(BOOTIMAGE_NAME_MCELF)-enc -else - @echo Boot image signing: Encryption is enabled. RSASSAPSS is enabled. - $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME_MCELF) --key $(APP_SIGNING_KEY) --enc y --enckey $(APP_ENCRYPTION_KEY) --kd-salt $(KD_SALT) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --enc_key_id $(APP_ENCRYPTION_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --pss_saltlen $(APP_SIGNING_SALT_LENGTH) --output $(BOOTIMAGE_NAME_MCELF_HS) --rsassa_pss - $(RM) $(BOOTIMAGE_NAME_MCELF)-enc -endif -endif - @echo Boot image: am261x:r5fss0-0:freertos:ti-arm-clang $(BOOTIMAGE_PATH)/$(BOOTIMAGE_NAME_MCELF_HS) Done !!! - @echo . -endif - - - -.PHONY: coverage -coverage: - @echo Creating Coverage Report for spi_10mhz.$(PROFILE) ... - $(MKDIR) coverage - $(PROFDATA) merge -sparse -obj-file=$(OUTNAME) $(OUTNAME).cnt -o spi_10mhz.$(PROFILE).profdata - $(COV) show --format=html --show-expansions --show-instantiations --show-branches=count --object=$(OUTNAME) -instr-profile=spi_10mhz.$(PROFILE).profdata --output-dir=$(COVERAGE_PATH)/coverage --ignore-filename-regex=build_jenkins - $(COV) export --format=text --object=$(OUTNAME) --instr-profile=spi_10mhz.$(PROFILE).profdata > coverage/spi_10mhz.$(PROFILE).profdata.json - node $(MCU_PLUS_SDK_PATH)/tools/smart_placement/clang_coverage_analyse.js --input=coverage/spi_10mhz.$(PROFILE).profdata.json --output-json=coverage/spi_10mhz.$(PROFILE).analysis.json --output=../spi_10mhz.annotations.$(PROFILE).S --top-function-count=500 - @echo Coverage Report Generated at $(COVERAGE_PATH)/coverage folder !!! - --include $(addprefix $(OBJDIR)/, $(DEPS)) diff --git a/examples/spi_10mhz/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/makefile.defs b/examples/spi_10mhz/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/makefile.defs deleted file mode 100644 index 4f41ac3..0000000 --- a/examples/spi_10mhz/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/makefile.defs +++ /dev/null @@ -1,14 +0,0 @@ -GEN_FILES__QUOTED += \ -*.appimage* \ -*.appimage_xip \ -*.rprc* \ -*.rprc_xip \ -*.tiimage* \ -*.bin \ -*.lnkxml \ -*.map \ -*.ossr - -GEN_FILES__QUOTED += \ -*.mcelf* \ -*.mcelf_xip diff --git a/examples/spi_10mhz/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/makefile_ccs_bootimage_gen b/examples/spi_10mhz/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/makefile_ccs_bootimage_gen deleted file mode 100644 index fe5c5f6..0000000 --- a/examples/spi_10mhz/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/makefile_ccs_bootimage_gen +++ /dev/null @@ -1,95 +0,0 @@ -# -# Auto generated makefile -# - -# Below variables need to be defined outside this file or via command line -# - PRU_NO_CODE_TOOL_PATH -# - MCU_PLUS_SDK_PATH -# - PROFILE -# - CG_TOOL_ROOT -# - OUTNAME -# - CCS_INSTALL_DIR -# - CCS_IDE_MODE - -CCS_PATH=$(CCS_INSTALL_DIR) -include $(PRU_NO_CODE_TOOL_PATH)/imports.mak -include $(MCU_PLUS_SDK_PATH)/devconfig/devconfig.mak - -STRIP=$(CG_TOOL_ROOT)/bin/tiarmstrip -OBJCOPY=$(CG_TOOL_ROOT)/bin/tiarmobjcopy -ifeq ($(OS), Windows_NT) - PYTHON=python -else - PYTHON=python3 -endif - -OUTFILE=$(PROFILE)/$(OUTNAME).out -BOOTIMAGE_PATH=$(abspath ${PROFILE}) -BOOTIMAGE_NAME_MCELF:=$(BOOTIMAGE_PATH)/$(OUTNAME).mcelf -BOOTIMAGE_NAME_MCELF_HS:=$(BOOTIMAGE_PATH)/$(OUTNAME).mcelf.hs -TARGETS += $(BOOTIMAGE_NAME_MCELF) -TARGETS += $(BOOTIMAGE_NAME_MCELF_HS) -ifeq ($(DEVICE_TYPE), HS) - TARGETS += $(BOOTIMAGE_NAME_MCELF_HS) -endif - -# -# Generation of boot image which can be loaded by Secondary Boot Loader (SBL) -# -ifeq ($(OS),Windows_NT) -EXE_EXT=.exe -endif -ifeq ($(OS),Windows_NT) - BOOTIMAGE_CERT_GEN_CMD=powershell -executionpolicy unrestricted -command $(MCU_PLUS_SDK_PATH)/source/security/security_common/tools/boot/signing/x509CertificateGen.ps1 -else - BOOTIMAGE_CERT_GEN_CMD=$(MCU_PLUS_SDK_PATH)/source/security/security_common/tools/boot/signing/x509CertificateGen.sh -endif -BOOTIMAGE_TEMP_OUT_FILE=$(PROFILE)/temp_stdout_$(PROFILE).txt - -BOOTIMAGE_CORE_ID_r5fss0-0 = 0 -BOOTIMAGE_CORE_ID_r5fss0-1 = 1 -BOOTIMAGE_CORE_ID_r5fss1-0 = 2 -BOOTIMAGE_CORE_ID_r5fss1-1 = 3 -SBL_RUN_ADDRESS=0x70002000 -SBL_DEV_ID=55 - -APP_IMAGE_SIGN_CMD = $(MCU_PLUS_SDK_PATH)/source/security/security_common/tools/boot/signing/mcu_appimage_x509_cert_gen.py -MCELF_IMAGE_GEN = $(MCU_PLUS_SDK_PATH)/tools/boot/multicore-elf/genimage.py - -all: -ifeq ($(CCS_IDE_MODE),cloud) -# No post build steps -else - - @echo Boot multi-core ELF image: am261x:r5fss0-0:freertos:ti-arm-clang $(BOOTIMAGE_NAME_MCELF) ... - - $(PYTHON) $(MCELF_IMAGE_GEN) --core-img=$(BOOTIMAGE_CORE_ID_r5fss0-0):$(OUTFILE) --output=$(BOOTIMAGE_NAME_MCELF) --merge-segments=$(MCELF_MERGE_SEGMENTS_FLAG) --tolerance-limit=$(MCELF_MERGE_SEGMENTS_TOLERANCE_LIMIT) --ignore-context=$(MCELF_IGNORE_CONTEXT_FLAG) --xip=$(MCELF_XIP_RANGE) --xlat=$(MCELF_ADDR_TRANSLATION_PATH) --max-segment-size=$(MCELF_MAX_SEGMENT_SIZE) - - @echo Boot multi-core ELF image: $(BOOTIMAGE_NAME_MCELF) Done !!! - @echo . - -ifeq ($(DEVICE_TYPE), HS) -# Sign the appimage using appimage signing script -ifeq ($(ENC_ENABLED),no) -ifeq ($(RSASSAPSS_ENABLED),no) - @echo Boot image signing: Encryption is disabled. - $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME_MCELF) --key $(APP_SIGNING_KEY) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --output $(BOOTIMAGE_NAME_MCELF_HS) -else - @echo Boot image signing: Encryption is disabled. RSASSA-PSS is enabled. - $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME_MCELF) --key $(APP_SIGNING_KEY) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --pss_saltlen $(APP_SIGNING_SALT_LENGTH) --output $(BOOTIMAGE_NAME_MCELF_HS) --rsassa_pss -endif -else -ifeq ($(RSASSAPSS_ENABLED),no) - @echo Boot image signing: Encryption is enabled. - $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME_MCELF) --key $(APP_SIGNING_KEY) --enc y --enckey $(APP_ENCRYPTION_KEY) --kd-salt $(KD_SALT) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --enc_key_id $(APP_ENCRYPTION_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --output $(BOOTIMAGE_NAME_MCELF_HS) - $(RM) $(BOOTIMAGE_NAME_MCELF)-enc -else - @echo Boot image signing: Encryption is enabled. RSASSA-PSS is enabled. - $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME_MCELF) --key $(APP_SIGNING_KEY) --enc y --enckey $(APP_ENCRYPTION_KEY) --kd-salt $(KD_SALT) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --enc_key_id $(APP_ENCRYPTION_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --pss_saltlen $(APP_SIGNING_SALT_LENGTH) --output $(BOOTIMAGE_NAME_MCELF_HS) --rsassa_pss - $(RM) $(BOOTIMAGE_NAME_MCELF)-enc -endif -endif - @echo Boot image: am261x:r5fss0-0:freertos:ti-arm-clang $(BOOTIMAGE_PATH)/$(BOOTIMAGE_NAME_MCELF_HS) Done !!! - @echo . -endif -endif diff --git a/examples/spi_10mhz/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/makefile_projectspec b/examples/spi_10mhz/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/makefile_projectspec deleted file mode 100644 index 16cc4cd..0000000 --- a/examples/spi_10mhz/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/makefile_projectspec +++ /dev/null @@ -1,16 +0,0 @@ -export PRU_NO_CODE_TOOL_PATH?=$(abspath ../../../../../..) -include $(PRU_NO_CODE_TOOL_PATH)/imports.mak - -PROFILE?=Release - -PROJECT_NAME=spi_10mhz_am261x-lp_r5fss0-0_freertos_ti-arm-clang - -all: - $(CCS_ECLIPSE) -noSplash -data $(PRU_NO_CODE_TOOL_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectBuild -ccs.projects $(PROJECT_NAME) -ccs.configuration $(PROFILE) - -clean: - $(CCS_ECLIPSE) -noSplash -data $(PRU_NO_CODE_TOOL_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectBuild -ccs.projects $(PROJECT_NAME) -ccs.configuration $(PROFILE) -ccs.clean - -export: - $(MKDIR) $(PRU_NO_CODE_TOOL_PATH)/ccs_projects - $(CCS_ECLIPSE) -noSplash -data $(PRU_NO_CODE_TOOL_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectCreate -ccs.projectSpec example.projectspec -ccs.overwrite full diff --git a/examples/spi_10mhz/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/syscfg_c.rov.xs b/examples/spi_10mhz/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/syscfg_c.rov.xs deleted file mode 100644 index f716f8e..0000000 --- a/examples/spi_10mhz/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/syscfg_c.rov.xs +++ /dev/null @@ -1,12 +0,0 @@ -/* - * ======== syscfg_c.rov.xs ======== - * This file contains the information needed by the Runtime Object - * View (ROV) tool. - */ -var crovFiles = [ - "kernel/freertos/rov/FreeRTOS.rov.js", -]; - -var objectViewerFiles = [ - "kernel/freertos/rov_theia/FreeRTOS_Theia.rov.js", -]; diff --git a/examples/spi_10mhz/mcuplus/empty_example.c b/examples/spi_10mhz/mcuplus/empty_example.c deleted file mode 100644 index f7bff9c..0000000 --- a/examples/spi_10mhz/mcuplus/empty_example.c +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2024-2025 Texas Instruments Incorporated - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 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. - * - * Neither the name of Texas Instruments Incorporated 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 - * OWNER 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. - */ - -#include -#include -#include "ti_drivers_config.h" -#include "ti_drivers_open_close.h" -#include "ti_board_open_close.h" -#include - -#include -#include - - - -/* - * This is an example project to show R5F - * loading PRU firmware. - */ - -/** \brief Global Structure pointer holding PRUSS1 memory Map. */ - -PRUICSS_Handle gPruIcss0Handle; - - -void empty_example_main(void *args) -{ - Drivers_open(); // check return status - - int status; - status = Board_driversOpen(); - DebugP_assert(SystemP_SUCCESS == status); - - gPruIcss0Handle = PRUICSS_open(CONFIG_PRU_ICSS0); - - status = PRUICSS_initMemory(gPruIcss0Handle, PRUICSS_DATARAM(PRUICSS_PRU0)); - DebugP_assert(status != 0); - - status = PRUICSS_initMemory(gPruIcss0Handle, PRUICSS_DATARAM(PRUICSS_PRU1)); - DebugP_assert(status != 0); - - status = PRUICSS_loadFirmware(gPruIcss0Handle, PRUICSS_PRU1, PRU1Firmware_0, sizeof(PRU1Firmware_0)); - DebugP_assert(SystemP_SUCCESS == status); - DebugP_log("----- PRU1 Firmware loaded successfully. SPI Slave initialized. \r\n"); - status = PRUICSS_loadFirmware(gPruIcss0Handle, PRUICSS_PRU0, PRU0Firmware_0, sizeof(PRU0Firmware_0)); - DebugP_assert(SystemP_SUCCESS == status); - DebugP_log("----- PRU0 Firmware loaded successfully. SPI Master initialized. \r\n"); - DebugP_log("----- Check register R0 of PRU0 to view the data recieved \r\n"); - - while (1) - { - ClockP_usleep(1); - } - - Board_driversClose(); - Drivers_close(); -} diff --git a/examples/spi_10mhz/readme.md b/examples/spi_10mhz/readme.md deleted file mode 100644 index 991c308..0000000 --- a/examples/spi_10mhz/readme.md +++ /dev/null @@ -1,169 +0,0 @@ -# SPI Transfer at 10MHz - -## Introduction - -This example demonstrates the use of the PRU No-Code Tool to achieve a 10MHz SPI clock on the AM261x platform using a PRU core clock of 200MHz. PRU0 acts as the SPI controller using the **SPI Transfer block** (full-duplex) and PRU1 acts as the SPI peripheral using the **SPI Write block**. - -The purpose of this example is to validate both directions of the SPI Transfer block: -- **TX path (PRU0 → PRU1)**: PRU0 transmits 32-bit data over SDO. Verified using a Saleae logic analyzer. -- **RX path (PRU1 → PRU0)**: PRU1 emulates an encoder response by driving known data (0xDEADDEAD) back over its SDO using the SPI Write slave block, which PRU0 receives via its SDI pin. This allows the RX path of the SPI Transfer block to be validated without requiring actual encoder hardware. - -After running the example the data recieved by the SPI transfer block is stored in register **R0 of PRU0** - -SPI mode used: **MODE1** (CPOL=0, CPHA=1). All 4 modes are supported. - -
-spi_10mhz -
In the figure, white signal represent the clock (70ns high and 30ns low) and the red signal represent the data (1 bit = 10ns)
-
- ---- - -## Timing Configuration - -| Parameter | Value | -|-----------|-------| -| PRU clock | 200 MHz (AM261x ZFG 400MHz variant) | -| SCLK high width | 14 PRU cycles | -| SCLK low width | 6 PRU cycles | -| SPI clock frequency | 200MHz / (14+6) = **10 MHz** | -| Data setup time | 50 ns (10 PRU cycles) | -| CS setup time | 500 ns | -| CS hold time | 500 ns | - -> **Note:** The SCLK high width of 14 cycles is the minimum achievable with a 50ns data setup time requirement. -> At 200MHz PRU clock: `ceil(50ns × 200/1000) = 10 cycles` data setup overhead, giving `high_min = 4 + 10 = 14 cycles`. - ---- - -## No-Code Tool Block Design - -### PRU0 — SPI Controller (Transfer block) - -``` -[Load Constant: Load_Constant_0] value = 0xABCDEFAB (32-bit data to transmit) - │ - ▼ -[SPI Transfer: PRU0_SPI_Transfer_0] full-duplex, controller mode, MODE1, 32-bit MSB first - │ SCLK high = 14 cycles, low = 6 cycles → 10MHz - │ Data setup = 50ns, CS setup = 500ns, CS hold = 500ns - │ SCLK → GPO0, SDO → GPO1, SDI ← GPI6, CS → GPO2 - ▼ -[Flow Control: Flow_Control_0] HALT -``` - -### PRU1 — SPI Peripheral (Write block) - -``` -[Load Constant: Load_Constant_0] value = 0xDEADDEAD (32-bit data to send back to controller) - │ - ▼ -[SPI Write: PRU1_SPI_Write_0] peripheral mode, MODE1, 32-bit MSB first - │ waits for CS assert from PRU0, then sends data on SDO - │ SCLK ← GPI4, SDI ← GPI5, SDO → GPO1, CS ← GPI6 - ▼ -[Flow Control: Flow_Control_0] HALT -``` - ---- - -## Block Configuration Details - -### PRU0 Blocks - -**Load Constant (`Load_Constant_0`)** -- Value: 2882400171 (0xABCDEFAB) — 32-bit test pattern to transmit - -**SPI Transfer (`PRU0_SPI_Transfer_0`)** -- Packet size: 32 bits -- Device mode: Controller -- SPI mode: MODE1 (CPOL=0, CPHA=1) -- Endianness: MSB first -- SCLK high pulse width: 14 PRU cycles -- SCLK low pulse width: 6 PRU cycles -- Data setup time: 50ns -- CS setup time: 500ns -- CS hold time: 500ns -- SCLK signal: GPO0 -- SDO signal: GPO1 -- SDI signal: GPI6 -- CS signal: GPO2 - -**Flow Control (`Flow_Control_0`)** -- Operation: HALT - ---- - -### PRU1 Blocks - -**Load Constant (`Load_Constant_0`)** -- Value: 3735936685 (0xDEADDEAD) — 32-bit test pattern PRU1 sends back to PRU0 to emulate the encoder response - -**SPI Write (`PRU1_SPI_Write_0`)** -- Packet size: 32 bits -- Device mode: Peripheral -- SPI mode: MODE1 (CPOL=0, CPHA=1) -- Endianness: MSB first -- SCLK signal: GPI4 -- SDI signal: GPI5 -- SDO signal: GPO1 -- CS signal: GPI6 -- CS filter cycles: 2 - -**Flow Control (`Flow_Control_0`)** -- Operation: HALT - ---- - -## Pin Connections - -PRU0 drives SCLK and CS; both PRUs drive their respective SDO lines. - -| Signal | PRU0 pin (controller) | PRU1 pin (peripheral) | -|--------|-----------------------|-----------------------| -| SCLK | GPO0 | GPI4 | -| SDO | GPO1 | GPO5 | -| SDI | GPI6 | ---- | -| CS | GPO2 | GPI6 | - ---- - -## Why SPI Write slave instead of SPI Transfer slave? - -The SPI Transfer slave (full-duplex peripheral) has a practical maximum frequency of **7.69MHz at 200MHz PRU clock** due to the polling overhead of the software-based slave. The slave needs ~13 cycles minimum in both high and low phases to detect edges reliably. - -The SPI Write slave (TX only peripheral) relaxes the low phase constraint since it does not need to sample SDI, allowing the controller's low width to go down to 6 cycles. This enables the 10MHz clock while still validating the RX path of the controller's Transfer block. - -In this example the SPI Write slave on PRU1 serves as an **encoder emulator** — it sends back a fixed known pattern (0xDEADDEAD) to simulate the response a real encoder would send over SPI. This lets the RX path of the Transfer block be fully tested at 10MHz without needing actual encoder hardware connected. - -For a full bidirectional loopback at 200MHz PRU clock, use `high=13, low=13` giving **7.69MHz**. For 333MHz PRU clock (AM243x), the practical max is **12.8MHz** with `high=13, low=13`. - ---- - -# Supported Combinations - - Parameter | Value - ---------------|----------- - ICSSM | ICSSM1 - PRU0, PRU1 (am261x only) - Toolchain | pru-cgt - Board | am261x-lp - Example folder | examples/spi_10mhz/ - -# Steps to Run the Example - -> Prerequisite: [PRU-CGT-2-3](https://www.ti.com/tool/PRU-CGT) (ti-pru-cgt) should be installed at: `C:/ti/` - -- **When using CCS projects to build**, import the CCS project from the above mentioned Example folder path for R5F and PRU. After this `main.asm`, `linker.cmd` files get copied to the CCS workspace of the PRU project. The `main.asm` contains sample code to halt the PRU program. - - - Build the PRU project using the CCS project menu (see [for AM261x](https://software-dl.ti.com/mcu-plus-sdk/esd/AM261X/latest/exports/docs/api_guide_am261x/CCS_PROJECTS_PAGE.html)). - - Build Flow: Once you click on build in PRU project, the firmware header file generated in the release or debug folder of the CCS workspace is moved to `` - - - Build the R5F project using the CCS project menu (see [for AM261x](https://software-dl.ti.com/mcu-plus-sdk/esd/AM261X/latest/exports/docs/api_guide_am261x/CCS_PROJECTS_PAGE.html)). - - The firmware header file path is included in R5F project include options by default. Instructions in the firmware header file can be written into PRU IRAM memory using the PRUICSS_loadFirmware API. - - - Launch a CCS debug session and run the executable (see [for AM261x](https://software-dl.ti.com/mcu-plus-sdk/esd/AM261X/latest/exports/docs/api_guide_am261x/CCS_LAUNCH_PAGE.html)). - - - Connect the SPI controller and peripheral pins as per the pin connections table above. - -- **When using makefiles to build**: - - For steps on how to use makefiles, run `make help` from the root folder of the pru-no-code-tool repository. diff --git a/examples/spi_loopback/firmware/am243x-lp/icss_g0_pru0_fw/example.syscfg b/examples/spi_loopback/firmware/am243x-lp/icss_g0_pru0_fw/example.syscfg index c8272eb..a71db23 100644 --- a/examples/spi_loopback/firmware/am243x-lp/icss_g0_pru0_fw/example.syscfg +++ b/examples/spi_loopback/firmware/am243x-lp/icss_g0_pru0_fw/example.syscfg @@ -26,7 +26,7 @@ load_constant_block1.$name = "Load_Constant_0"; load_constant_block1.constant1 = 2882382797; flow_control_block1.$name = "Flow_Control_0"; -flow_control_block1.opCode = "HALT"; + pru_spi_write1.$name = "PRU_SPI_Write_0"; pru_spi_write1.packetSize = 32; diff --git a/examples/spi_loopback/firmware/am243x-lp/icss_g0_pru1_fw/example.syscfg b/examples/spi_loopback/firmware/am243x-lp/icss_g0_pru1_fw/example.syscfg index dce012a..f600106 100644 --- a/examples/spi_loopback/firmware/am243x-lp/icss_g0_pru1_fw/example.syscfg +++ b/examples/spi_loopback/firmware/am243x-lp/icss_g0_pru1_fw/example.syscfg @@ -18,7 +18,7 @@ const pru_spi_read1 = pru_spi_read.addInstance(); * Write custom configuration values to the imported modules. */ flow_control_block1.$name = "Flow_Control_0"; -flow_control_block1.opCode = "HALT"; + pru_spi_read1.$name = "PRU_SPI_Read_0"; pru_spi_read1.packetSize = 32; diff --git a/examples/spi_loopback/firmware/am261x-lp/icss_m1_pru0_fw/example.syscfg b/examples/spi_loopback/firmware/am261x-lp/icss_m1_pru0_fw/example.syscfg index 31a0958..06ff9bd 100644 --- a/examples/spi_loopback/firmware/am261x-lp/icss_m1_pru0_fw/example.syscfg +++ b/examples/spi_loopback/firmware/am261x-lp/icss_m1_pru0_fw/example.syscfg @@ -26,7 +26,7 @@ load_constant_block1.$name = "Load_Constant_0"; load_constant_block1.constant1 = 3735928559; flow_control_block1.$name = "Flow_Control_0"; -flow_control_block1.opCode = "HALT"; + pru_spi_write1.$name = "PRU0_SPI_Write_0"; pru_spi_write1.packetSize = 32; diff --git a/examples/spi_loopback/firmware/am261x-lp/icss_m1_pru1_fw/example.syscfg b/examples/spi_loopback/firmware/am261x-lp/icss_m1_pru1_fw/example.syscfg index 46d0fcb..12ffff5 100644 --- a/examples/spi_loopback/firmware/am261x-lp/icss_m1_pru1_fw/example.syscfg +++ b/examples/spi_loopback/firmware/am261x-lp/icss_m1_pru1_fw/example.syscfg @@ -18,7 +18,7 @@ const pru_spi_read1 = pru_spi_read.addInstance(); * Write custom configuration values to the imported modules. */ flow_control_block1.$name = "Flow_Control_0"; -flow_control_block1.opCode = "HALT"; + pru_spi_read1.$name = "PRU1_SPI_Read_0"; pru_spi_read1["SCLK Signal"] = "4"; diff --git a/examples/spi_loopback/firmware/main.asm b/examples/spi_loopback/firmware/main.asm index dcd1f1e..0e4e88f 100644 --- a/examples/spi_loopback/firmware/main.asm +++ b/examples/spi_loopback/firmware/main.asm @@ -34,3 +34,4 @@ main: JMP sysconfig_generated_start +sysconfig_generated_end: diff --git a/examples/spi_loopback/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/example.projectspec b/examples/spi_loopback/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/example.projectspec index 2d5cae5..7321e38 100644 --- a/examples/spi_loopback/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/example.projectspec +++ b/examples/spi_loopback/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/example.projectspec @@ -12,7 +12,7 @@