To enable user customization of the POV message, my approach is to allow the user to write the message in ASCII characters and send it to the PFC232 microcontroller via I2C. In this setup, the PFC232 will function as an I2C slave, which is a bit unconventional, as microcontrollers typically act as I2C masters, such as when reading data from the ADXL345 sensor. In my case, the microcontroller must act as BOTH a master (for reading the ADXL345), and also a slave for handling the upload of I2C messages from the user.
The Padauk FPPA IDE has a very nice tool to generate boilerplate code for I2C slave, which can handle multiple-byte buffer write and reads.
void I2C_Slave (void)
{
$ I2C_SCL_Slave In;
$ I2C_SDA_Slave In;
.delay 99; // Wait for master ready
addr$1 = 0; // at the sample code, only access one byte of address.
Stop:
.wait1 I2C_SCL_Slave
if (! I2C_SDA_Slave) goto Stop;
High: if (! I2C_SCL_Slave) goto Stop;
if (I2C_SDA_Slave) goto High;
Start: if (! I2C_SCL_Slave) goto Chk_Ax;
if (! I2C_SDA_Slave) goto Start;
goto High;
Chk_Ax:
BYTE count = DEVICE_LEN;
A = I2C_SLAVE_DEVICE;
do
{
sl A;
.wait1 I2C_SCL_Slave
if (I2C_SDA_Slave)
{
if (! CF) goto Stop;
while (1)
{
if (! I2C_SCL_Slave) break;
if (! I2C_SDA_Slave) goto Start;
}
}
else
{
if (CF) goto Stop;
while (1)
{
if (! I2C_SCL_Slave) break;
if (I2C_SDA_Slave) goto Stop;
}
}
} while (--count);
if (DEVICE_LEN != 7)
{
BYTE hi_adr = 0;
A = 7 - DEVICE_LEN;
do
{
.wait1 I2C_SCL_Slave
if (I2C_SDA_Slave)
{
CF = 1;
slc hi_adr;
while (1)
{
if (! I2C_SCL_Slave) break;
if (! I2C_SDA_Slave) goto Start;
}
}
else
{
sl hi_adr;
while (1)
{
if (! I2C_SCL_Slave) break;
if (I2C_SDA_Slave) goto Stop;
}
}
} while (--A);
}
.wait1 I2C_SCL_Slave
BYTE data;
if (I2C_SDA_Slave)
{ // Read
while (1)
{
if (! I2C_SCL_Slave) break;
if (! I2C_SDA_Slave) goto Start;
}
$ I2C_SDA_Slave Out, Low;
.wait1 I2C_SCL_Slave
Send: count = 8;
data = ~ *addr;
addr$0++;
do
{
.wait0 I2C_SCL_Slave
sl data;
#if _SYS(OP:SWAPC IO.N)
swapc _PXC(I2C_SDA_Slave);
#else
if (!CF) $ I2C_SDA_Slave In;
if (CF) $ I2C_SDA_Slave Out;
#endif
$ I2C_SDA_Slave Low;
.wait1 I2C_SCL_Slave
} while (--count);
.wait0 I2C_SCL_Slave
$ I2C_SDA_Slave In;
.wait1 I2C_SCL_Slave
Watch: if (I2C_SDA_Slave) goto Stop;
if (I2C_SCL_Slave) goto Watch;
goto Send;
}
// Write
while (1)
{
if (! I2C_SCL_Slave) break;
if (I2C_SDA_Slave) goto Stop;
}
$ I2C_SDA_Slave Out, Low;
.wait1 I2C_SCL_Slave
addr$1.0 = 1;
while (1)
{
.wait0 I2C_SCL_Slave
$ I2C_SDA_Slave In;
count = 8;
do
{
.wait1 I2C_SCL_Slave
if (I2C_SDA_Slave)
{
CF = 1;
slc data;
while (1)
{
if (! I2C_SCL_Slave) break;
if (! I2C_SDA_Slave) goto Start;
}
}
else
{
sl data;
while (1)
{
if (! I2C_SCL_Slave) break;
if (I2C_SDA_Slave) goto Stop;
}
}
} while (--count);
$ I2C_SDA_Slave Out, Low;
.wait1 I2C_SCL_Slave
if (addr$1.0) addr = data;
else
{
*addr = data;
addr$0++;
//Set Message Transfered Flag
MsgFlag = 1;
}
}
}
Initially, I planned to allow users to upload custom messages on the fly, but it turned out to be more challenging than expected with my current hardware setup. The issue arose because both the master and slave I2C devices shared the same SCL and SDA lines, leading to conflicts when they attempted I2C transactions simultaneously. Since the Padauk environment doesn't natively support MUTEX operations, managing these conflicts became difficult.
To resolve this, I simplified the design. Now, the user can only upload a message at the start of the operation. Once the message is uploaded, the LEDs will blink, and the POV display will show the message. No new messages can be uploaded during operation. The only way to change the message is to restart the POV display and upload a new one.
This made the software implementation much easier. I used a simple state machine in which State 0 waits for the user to upload the message (in I2C Slave mode). Once the message is uploaded, it transitions into State 1, where the I2C Master takes over the SCL and SDA lines. In this state, the ADXL345 is initialized and configured to the right settings. Then comes State 2, where it polls the ADXL345 and synchronizes the scanning of the virtual columns of the POV display.
I also encountered a RAM limitation issue. The PFC232 microcontroller is quite affordable, but it only comes with a small 128-byte data RAM, which is shared between the two FPPA units. Initially, I wanted the POV display to support up to 20 characters, but I discovered that 12 characters is the actual limit. In hindsight, 12 characters turned out to be a practical limit as well. If the message is too long, the user would need to wave the display faster and over a greater distance. Beyond a certain point, the message becomes too long to display properly, given the user's realistic waving speed.
With all these challenges finally resolved, including addressing the PCB's cosmetic issues, I moved forward and sent the design for a new PCB production cycle. Now, it's just a matter of waiting for the new PCBs and parts to arrive so I can begin the process of mass manufacturing.
In the meantime, I'll be focusing on fine-tuning my LumenPnP Pick and Place machine to get it ready for this production run. It's essential to ensure the machine is calibrated precisely for this particular job, as it will be handling small components with high accuracy and speed.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.