-
DTMF tones and states
10 hours ago • 1 commentIt's been a week, and I've spent time on the project now and then.
With the keypad working, I need to output the dialing tones and DTMF tones for each digit pressed as a line level signal. I want the tones play when testing the keypad matrix further.
I've never worked with audio stuff at component level before so this is a great opportunity for learning. I've decided to use a 12-bit DAC to output the tones to an Op-amp as Pre-amp and Buffer which should then be fed into the codec AUX input. For testing I'm going to feed the signal to an amplifier connected to a small breadboard speaker. I was missing some components so I have ordered them.
While waiting for more components, I continued to work on the software side. I need to store the data for each tone in lookup tables so the CPU doesn't need to calculate them at run time.
I've also decided to add another state, a key pressed state. The code will enter this state when a key is pressed on the keypad, check which key is pressed and output the DTMF tone until the key is released. When you release the key, it will store the key pressed in a vector, keeping track of the digits pressed. It will then transition back into the dialing state. This time the dialing input timer is started and the dial tone is turned off. If the timer expires the code will transition into the calling state, where it will try to call the entered number.
I think I need a new state for when the recipient hangs up. It should play the tone to indicate this.
If you leave the handset off for some time, it will play the handset off alert tones and, if there is no input for a set time, go to sleep. Can I have the modem register the phone as busy, while it self goes to sleep? Handset off = no calls :)
Should the phone be set as busy? It might be better not to have it as busy? Would the caller keep trying, thinking that the phone is in use? What settings can be done in the modem?What other tones might I need? Perhaps if you try to make a call without reception? Low battery?
Holding down the R key while lifting the handset, should it be put into speed dial mode?
Holding down the R key during the dialing or active call goes into command mode, where you can adjust the volume and other settings using the keypad.
I also need to check for the reset switch, if activated it should return to dialing state with a clean slate.
-
Keypad matrix scanning success
7 days ago • 0 commentsI double-checked all connections and didn't notice any mistakes. I was able to program the SLG46826V, but it was not functioning. It gets no power. I removed the regulator, tested it, and it worked. Then I noticed the regulator was not connected to the power rail on the far left side, which powers the SLG46826V module. I was so focused on looking for short circuits that I missed it, I guess.
Now I've implemented the function that reads from the SLG46826V and determines which key is pressed. I need to do some more testing, but based on initial testing of the keypad, it seems to work without issues.
The keypad matrix scanning is almost complete! :)
-
Breadboard setup for user input
01/07/2025 at 21:48 • 0 commentsHere is what the breadboard looks like now.
I pinned the DIAVOX mainboard onto the breadboard using solid core wire. It's connected to the SLG46826V module, which has been connected to the Pico Lipo via I2C and GPIO. The regulator powers the SLG46826V module, and I connected a LED so I can see that it is powered. I have two jumper wires from the SLG46826V module, one going to the keypad-matrix active and the other from programming good signal to a LED. The orange push-button have been connected as the R button and the toggle switch acts as the handset switch. The handset switch reset has also been connected.
With this set up, I can write the code for collecting the keys pressed and, troubleshoot the keypad matrix scanning design. I can also implement the reset switch functionality, collect the numbers pressed, switch states from user input to dialing, and turn off everything with the handset switch.
I mentioned before that I would use an ISR for the keypad active signal, but since we are only in the user input state when the handset is off, I've decided to just poll the signals. I might revisit this some other time if it could reduce power consumption.
I've implemented functions to check all of the newly added signals. Before powering anything up, I have to double-check all the connections. I will do that next time, as today's project time has run out.
-
Breadboarding
01/06/2025 at 21:28 • 0 commentsThis morning I spent some time breadboarding. I removed everything on the main breadboard, and started from scratch with a new layout. I thought about how to set it up so I will have enough space for all other components needed.
The SLG46826V module has a new home on the main breadboard. I will use the ICSP capabilities to program it, once the design is finalized I will write it to the NVRAM.
Now with the breadboard set up, I need to revisit the main project code. I need to read the LUT's and determine which key is pressed.
I've also been looking at the bell ringer part a little bit, and I've found an IC that could be used to make a new better PSU. Looked at gate drivers, and N-Channel H-bridge designs.
-
Setting up the keypad
01/04/2025 at 02:27 • 0 commentsIn the last log entry I mentioned that there might be something wrong with my code as I cannot write to the first byte. I tried writing to it using the same function that writes to the reset register, but that doesn't work either.
There might be a problem with how the MCP2221A handles the command, the default address for the SLG46826V is 0x01, which is one of the reserved I2C addresses. Perhaps this could be the issue with the first byte. I could change the device's slave address and try writing again. For now, though, I'll continue working on the keypad matrix scanning design and revisit this problem later. I replaced that LUT with another LUT, and it seems to work fine.
I've soldered a socket header to the DIAVOX mainboard which can be used to attach wires to the SLG46826V.
The SLG46826V should handle debouncing, disallow multiple keys from being held down simultaneously, and send the key pressed output signal. The pico could just read the registers via I2C to get which key is pressed. For now the key pressed signal will just be connected to a LED, so I can see that a key is being pressed. The keypad scanning part in the SLG46826V should be enabled/disabled by the handset switch. I'll probably have some resources left in the SLG46826V for some other purposes.
I referred to the design in the "AN-1113 Security Door Lock with Keypad Entry" application note and copied the design for the keypad matrix scanning.
The keypad matrix scanning works perfectly. I added an output so I could tell when the SLG46826V have been programmed, for troubleshooting. If any of the keys are pressed an output signal is created. I just randomly selected the pinout, so I might readjust it later. I also need to add functionality to allow the scanning to be started or stopped using the handset switch.
I checked the output with my oscilloscope, and it looks solid.
-
Solved it
01/02/2025 at 01:40 • 0 commentsI was grasping for straws this whole time, searching for something that didn't exist, a secret emulate mode.
In my last post I looked at the official hardware debug tool and I was just overthinking it, it's just protection features. While going over the datasheet, it seemed the only issue preventing my design from working was the first byte that can't be set.
Looking in GPD, it’s a LUT. I'll try using another LUT and see if I have the same problem. Now the design seems to have been written to the chip but it doesn't work, I checked the connections in GPD... I've missed a connection to one of the timers...
The test design works now. Holding the button down for 3 seconds turns the LED on; holding it down for 8 seconds turns it off.Now let's go back and use the LUT I did before. It does not work. Is there a problem with my code? The first byte does not write properly? I'll have to go through my code and perhaps write some tests.
I've not wasted any time though since I've learned a lot from this. I wrote a lot of code to test all kinds of stuff. I looked more closely at the protection features of the SLG46826 and got a better understanding of how it works.
I do feel a bit stupid for assuming that emulate mode was a secret, I also made faulty assumptions about all kinds of things.
As with all other mistakes I've made, I learned a lot. ;) -
The search for GreenPAK Emulate Mode
12/31/2024 at 20:38 • 0 commentsMaybe to use emulate mode, you need to set the I2C address to something other than the default? The slave address is set using the register byte CA. The first 4 bits are set if you want to use I/O pins to set it, like an EEPROM, for example. The last 4 bits are used to set the slave address; then you can have up to 16 unique addresses.
Well, it doesn't seem to have anything to do with it.
Reading through the datasheet, there is a section on read and write protection of the registers...
reg[1793:1792]: 2k Register Read Selection Bits RPRB[1:0] -> 00: 2k register data is unprotected for read; 01: 2k register data is partly protected for read; 10: 2k register data is fully protected for read; 11: reserved <-- this is interesting.
reg[1795:1794]: 2k Register Write Selection Bits RPRB[3:2] -> 00: 2k register data is unprotected for write; 01: 2k register data is partly protected for write; 10: 2k register data is fully protected for write; 11: reserved <-- this again.
Could these configuration bits lock the set mode? Apparently not; this is from the datasheet.
"Protect Lock Bit (PRL): The Protect Lock Bit is used to permanently lock the current state of the WPR, as well as RPR and NPR (see Section 15.5). A Logic 0 indicates that the WPR, RPR, and NPR can be modified, whereas a Logic 1 indicates the WPR, RPR, and NPR has been locked and can no longer be modified. The PRL register bit is located at register [1824] address."
Setting the PRL register bit will permanently set the current state of the RPR. So reg [1824] is a scary bit. Now, is this only scary if you write it to NVRAM? I do not want to test this either.
I should be able to safely set anything in the RPR [E0] register byte. There are 2 bits for read and 2 bits for write modes, and 4 singular bits that are reserved in the datasheet. This byte could have something to do with emulate mode.
I set both read and write to 11 (reserved), but it had some effect as writing to registers didn't work. I tried setting each of the other bits individually with no effect. Then I tried combinations of these 4 registers with no effect either. I set all bits with no effect. I simply cannot write these 4 bits at all.
I found a document ("In-System Programming Guide SLG46824/6/7-A") that mentions what the last page is for:
"Service Page Page #15 inside the 2Kbits NVM Registers memory space contains reserved information that is preprogrammed during device final test. The information on this page can be read but not written by the user. As this page cannot be altered by the user, the programming algorithm does not need to address this page."
Now, is this why the GPD just wants all these to be 0, since they don't write that last page? I can ignore these? Still doesn't explain why I can't write to the other register bytes required by the design.
It's a good find; I can just ignore the last page for now.
I will start by looking at the datasheet registers table under the reserved portion for singular registers that are not part of the last page. This leaves us with 2 register bytes: CE and CF, with 10 registers to try. E0 I already tried. I'll leave E1 (NPR) and E3 (ERSE) alone.
CE: 4 singular bits CF: 6 singular bits
E0: 4 singular bits (already tried here) E1: 6 singular bits (NPR, probably nothing to do with emulate mode, will leave these alone) E3: 2 singular bits (Erase registers, will not touch these for now)
So if emulate mode is a single settable register, it would be highly likely one of these 10 registers.
The CE register byte doesn't respond to writes, so those 4 registers have nothing to do with emulate mode. CF register doesn't respond to writes either, so those 6 bits are probably not related to emulate mode.
They also refer to emulate mode as (sync). What does this mean?
In the datasheet, there is an 'I2C serial command register map.' It specifies the exact behavior I have. That, reg[74~79];[7B] are read-only even with the RPR in unlock. In the table, there is no mode in the RPR that unlocks these registers. The current values for the counters, reg[7C~7F, can be read but not written to; that makes sense. The table mentions a test mode. Now, what is this? Everything seems to be read-only except for reg[00~47], which shows no read or write. This could be the reserved mode for RPR. I tested it and was not able to write to anything; it probably has nothing to do with emulate (sync) mode.
There is a note that is numbered, but it's not mentioned anywhere else, so there is no context for it: "Note 2 R/W Readable/writable depend on the 'Trim mode enable' bit. If 'Trim mode enable' bit value = 1, then trim bits are enabled." Now, what is trim mode? This is the only line in the datasheet where it is mentioned at all.
There is a note below the other notes: "It is possible to read some data from macrocells, such as counter current value, connection matrix, and connection matrix virtual inputs. The I2C write will not have any impact on data in case data comes from macrocell output, except Connection Matrix Virtual Inputs. The silicon identification service bits allow identifying silicon family, its revision, and others."
The last page contains the silicon identification service bits.
Reading through the Power-On Reset pages in the datasheet, I found something that might be a clue: "The POR system generates a sequence of signals that enable certain macrocells." and "First, the on-chip NVM memory is reset. Next, the chip reads the data from NVM and transfers this information to a CMOS LATCH that serves to configure each macrocell, and the Connection Matrix which routes signals between macrocells. The third stage causes the reset of the input pins and then enables them. After that, the LUTs are reset and become active. After LUTs, the Delay cells, OSCs, DFFs, LATCHES, and Pipe Delay are initialized. Only after all macrocells are initialized, the internal POR signal (POR macrocell output) goes from LOW to HIGH (POR_OUT in Figure 89). The last portion of the device to be initialized is the output pins, which transition from high impedance to active at this point."
Does the emulate (sync) mode set something with the Power-On Reset, so it skips a step and leaves these macrocells configurable?
The official debug tool for multiple-time programmable devices is just connected by VDD, SCL, SDA, and GND. Perhaps the official debug tool is not just an MCP2221A device with tons of protection stuff; there is actually a PowerPAK and a GreenFET on it.
The GPIO from the MCP2221A is used for ACMP, ERROR, SEL0, and SEL1. These are connected to a SLG46582V. Looking at the datasheet and the circuit diagram for the official debug tool, the PowerPAK SLG46582V has 2 LDOs; one of them is connected to the GreenFET. Another pin is connected to the GreenFET (FET_ON). After this GreenFET, there is a circuit with a voltage divider connected to ACMP and a transient voltage protection circuit. Now, is this all only for the over-voltage protection? Or are SEL0 and SEL1 used to enable emulate mode?
The problem is, if I don't use emulate mode, I only have 1000 writes, so if I have problems with the design, I could go through these quickly.
Maybe I'm just searching for a needle in a haystack?
Happy new year!
-
GreenPAK problems
12/30/2024 at 19:47 • 0 commentsI made a function to read the GPD project file and extract the nvmData portion into a vector which is then used by a function to sequentially write to all registers. When trying to write to all registers of the device in one go, it seems like some of them could not be written to.
I reset the device, read all registers, program the device, read registers and then compare the before, after and the wanted register settings. Putting a diff next to each where after and wanted does not match. Now I can see which bytes that could not be written to, at least those that should have a different value than 0.
Perhaps you have to do 16-byte page writes to RAM as well. I made a new function to 16-byte Page write all 256 bytes. Results were better but I'm are still missing some critical registers for some reason.
Here is a list of the register bytes that could not be written to. I looked at the data sheet to see what they are used for.
Address Before After Wanted --------------------------------------------- 0x00 00 00 86 <- Diff! : Matrix output 0 0x78 01 03 00 <- Diff! : Matrix inputs 32 to 39 <-- Here we have a totally different value.. ?? 0x7B C0 C0 00 <- Diff! : Matrix inputs 56 to 63 0x7C 00 01 00 <- Diff! : CNT0(16-bit) Counted Value <-- Are these just the current counter value? 0x7E 00 FF 00 <- Diff! : CNT2(8-bit) Counted Value 0x7F 00 01 00 <- Diff! : CNT4(8-bit) Counted Value Are the registers below sort of settings or manufacturing code? left over test stuff? since GPD wants to reset them all. 0xCE 0E 0E 00 <- Diff! : Reserved with split register bits in data sheet 0xF0 3D 3D 00 <- Diff! : Reserved with split register bits in data sheet 0xF1 11 11 00 <- Diff! : Reserved with split register bits in data sheet, 1 unspecified bit (unused bits?) 0xF2 0D 0D 00 <- Diff! : Reserved with split register bits in data sheet, 3 unspecified bits (unused bits?) 0xF3 29 29 00 <- Diff! : Reserved with split register bits in data sheet, 2 unspecified bits (unused?) 0xF4 25 25 00 <- Diff! : Reserved with split register bits in data sheet, 2 unspecified bits (unused?) 0xF5 1F 1F 00 <- Diff! : Reserved with split register bits in data sheet, 2 unspecified bits (unused?) 0xF6 10 10 00 <- Diff! : Reserved with split register bits in data sheet 0xF7 FF FF 00 <- Diff! : Reserved full byte 0xF8 FF FF 00 <- Diff! : Reserved full byte 0xF9 02 02 00 <- Diff! : Reserved with split register bits in data sheet 0xFA B8 B8 00 <- Diff! : Reserved with split register bits in data sheet, 4 unspecified bits (unused?) 0xFB 06 06 00 <- Diff! : Reserved full byte 0xFC 84 84 00 <- Diff! : Reserved full byte
Some reserved bytes have their listing split in the data sheet with some of the bits not reserved. There is several ways to think about these reserved register bits. They have some functionality that GPD use, they are non functioning macrocells (silicion that doesn't work or part of it), there are some registers that aren't marked with reserved, are these unused registers?
The critical ones are these for the matrix output and inputs. I do successfully write to other matrix registers. So I'm not sure what is going on. Since I can not even do just a single byte write to the first register byte. The code is pretty much the same to write to the reset register and resetting works. I reset the device each time before I try to set the registers. Something else is going on.
I tried adding a 100ms delay before writing each page but that doesn't make any difference. I tried removing the connected switch and LED. I disconnected the EEPROM and the level shifter from I2C bus. No difference.
It's very easy to just change the control byte and write to NVRAM instead. I'm going to do some further troubleshooting before committing to that. I pretty sure you should be able to just write to RAM since the offical tool does it. Maybe you have to write in a different order. I'll try writing the pages backwards. Nope writing the pages from last to first made no difference at all. Is there a magic bit?
Looking through the datasheet there is a register bit 1600, I have no idea what it does but it's close to the reset bit. It's a long shot but I'm going to set this bit to 1 before writing. This bit can not be set. Nothing happens.
I'll try to disable IO latching. This bit can not be set either.To write to the NVRAM it first has to be erased. Looking at the notes for register [1823] Erase Enable(ERSE) it says "0: erase disable
1: cause the NVM erase: full NVM (4k bits) erase for
ERSCHIP = 1 (reg[1973]) if DIS_ERSCHIP = 0
(reg[1972]) or page erase for ERSCHIP = 0 (reg[1973]).".So reg[1973] ERSCHIP: Erase chip selects if you should erase all the NVRAM pages with the ERSE register.
reg[1972] DIS_ERSCHIO: Does this disable erasing the whole chip? but allows erasing pages? or does it disable erasing all together?Interesting, that it mentions two reserved registers. So there might be something that has to be done to enable "Emulation mode" where you can write to all RAM registers. I only found 1 library to write to the SLG46824/6 that mentions a emulate mode command but no code for it. So it is probably safe to say that it will not work without doing something special. Now if this is a secret bit? or something else I do not know.
If I had an offical tool and a tool to analyze the I2C traffic, I could find out. Setting reserved register bits until it work is probably not a very good idea. However since I'm operating on RAM any changes should be erased when I cut the power, but ERSE and other commands are executed through setting RAM registers. I can probably not write to anything critical without the emulate mode enable anyway? Should I try and perhaps sacrifice a SLG46826V module?
Emulate mode is important if I want to use any other greenPAK's since most are just one-time programmable. I could ask on the forums, but would they answer? If it's not in the datasheet is it a secret?
-
Setting the registers of the SLG46826V
12/28/2024 at 22:02 • 0 commentsEarlier, I mentioned that you have to write in 16-byte pages to the device. This applies only when writing to the NVRAM, probably as a safeguard to protect it from faulty code.
This means I should be able to perform a 256-byte write with all the register data, which I load from the project file using an XML library. Before doing that, I need to test writing to the registers.
I chose IO12 because it isn't connected to anything, and I successfully changed its configuration using the byte write function I created. Afterward, I implemented a reset function: if you write a 1 to register 1601, it resets the device and reloads settings from NVRAM. This worked perfectly, and the device returned to factory defaults. I suppose we have to treat register 1601 as a "scary bit" during NVRAM programming. Could it send the device into a boot loop, or is it disabled in the NVRAM? I don't want to find out.
Next, I need to include the XML library, read the NVRAM portion from the selected project file, feed that into our register_data vector, and send it. If successful, the device should have the functionality I specified from the cookbook example.
Suddenly, from the dark corners of the room, feature creeps appeared, or are they scope creeps? One of them suggested, "You should make an awesome CLI interface for the SLG46826V GreenPAK program!" Another one chimed in, "You should use TUI and include all the cool stuff!" Then, someone quickly interjected, "Cursive is the way to go. It's a tool and shouldn't be bloated." The discussion was on, but I tried to ignore them. Still, another voice said, "We should use another SLG46826V to manage power for all systems!" Yet another stepped out of the shadows, saying, "There are PowerPAKs for that purpose, and we should use one of those instead!" I made a note for the later stages of the project, where I will look at power management.
-
Realization and code refactoring
12/27/2024 at 21:27 • 0 commentsYesterday, I had a bug in my code when reading from the SLG46826V, it turned out to be that there was no grace period between commands to the MCP2221A. At work it suddenly popped up in my mind, maybe the other problems with the MCP2221A could be because of no grace time.
I started adding the grace time everywhere without realizing that I could just add it twice, since most code executes commands using the two same functions... stupid me. I'm going to refactor the code. I simply added the grace time to the send_command and read_response. Now I could remove all the other grace time before all the calls to these functions. Now I need to backup my code, before refactoring further.
I should probably move all MCP2221A related code into it's own library. Sadly no time for that today.