Problem with interrupts and output pins...

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

I'm still stuck on a couple of things with my project. This is a project to add SD storage and BLE communications to a 1982 pocket computer. I'm trying to interface the PSoC to LH5801 CPU by emulating RAM. I am able to write data from the MCU to the CPU, but things are breaking down when I try to read the data bus and use the R/W signal.

   

Right now, I have a decoded CS on P0.5. This has an interrupt on falling edge that triggers the main routine to read the address bus and see what needs to be done. The R/W line goes to P0.4, and is also ANDed with the inverted CS signal to control OE of the data bus pins.

   

Looking at the timing diagrams for the PC, it seems that R/W pulses low after address and data are set up when writing to memory. So, I would like to have an interrupt on R/W that gets enabled when CS goes low, and disabled when CS goes high. The W interrupt handler would then read the data bus and write the data to MCU memory.

   

The problem I'm stuck on is that I can't find how to enable interrupts for both P0.4 and P0.5, and, when I tried to move R/W to one of the remaining available pins (P4.0-1, or P5.0-1) the designer tells me that the function is not reachable from those pins. I can't use anything on P1, P2, or P3, because those ports are fully allocated for address and data lines.

   

I thought there was a way to have more than one interrupt per port. Can someone tell me more about this, or how I can use P4 or P5?

   

Thanks,
​Paul

0 Likes
1 Solution
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

For (most) PSoC4 chips all ports >= 4 cannot be routed to a signal but can be read or written to by firmware.

   

The only remaining pins are P0_6 and P0_7 which are currently used for debugging.

   

Consider connecting the interrupts to the signals coming from the input pins (or the output of the not-gate).

   

 

   

Bob

View solution in original post

0 Likes
14 Replies
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

For (most) PSoC4 chips all ports >= 4 cannot be routed to a signal but can be read or written to by firmware.

   

The only remaining pins are P0_6 and P0_7 which are currently used for debugging.

   

Consider connecting the interrupts to the signals coming from the input pins (or the output of the not-gate).

   

 

   

Bob

0 Likes
Anonymous
Not applicable

Hmmm... one thing I wanted to try, since it's supposed to be faster, was using CY_GET_REG8 and CY_SET_REG8 instead of Read and Write... however, these don't seem to work. If I replace:

   

Pin_Data_Write(buffer[laddress]);

   

with

   

CY_SET_REG8(CYREG_PRT1_DR, buffer[laddress]);

   

I get only 255/FF back in the results. Is this something that doesn't work for PSoC4? Are there other approaches that will work with this MCU that can speed up port reads and writes?

0 Likes
Anonymous
Not applicable

One other issue:

   

I added some logic in my TopDesign to NOR the CS and RW signals.This will go high only when I get a Write (low) while CS is enabled (low). I attached a rising edge interrupt to this and wrote a handler for it. I then modified my CS handler to enable the Write handler only after the address has been read and the data at the address location has been written to the data bus.

   

The problem I'm having is that, even if I leave the Write handler disabled forever, it still causes my data reads to return garbage. If I don't start it at all, I'm fine, though. I would have thought that a disabled handler and a never-started handler would incur the same timing costs, but that does not appear to be the case. Any idea what's happening here?

   

Update: I've found that this behavior changes if I move the Global Interrupt enable call to after the call where I start and disable the Write interrupt.

0 Likes
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

And one last update for now. With the current (attached) version of the project, my HELLO WORLD read works, as many times as I want to run it, with the Write handler in place, and being enabled each time the address has been read... but, once I try to actually write any data (POKE to some address), read stops working, and instead gets 0 from each address. In other words, once the write interrupt gets triggered a first time, it breaks something in handling all subsequent reads.

   

I would guess that, other than just being weirdness, there is something I need to do to reset the interrupt state for Write, but I haven't found any options. ClearPending doesn't seem to make any difference.

   

The one encouraging point about this is that it does seem that the interrupt is getting triggered...

0 Likes
Anonymous
Not applicable

I tried something different: I dropped the interrupt handling and instead added the function below to the FOR loop. Basically, I was finding a bunch of weird behavior with the interrupt handler... adding conditional logic further down would cause different behavior near the top.

   

With this function being called in the FOR loop, I can read and write data between the MCU and CPU. This is progress, but it's not ideal. The main issue I have with it is that this won't allow me to let the MCU sleep when idle. I read in one of the interrupt ANs that there is 16 clock cycles of overhead to calling an interrupt. I'm guessing that that's part of what I'm seeing and why this looped routine works. Any other suggestions on how I can make this work through an interrupt handler instead of a continuous loop?

   


void ProcessReq()
{
    if (!(CyPins_ReadPin(Pin_CS_0)))
    {
        //ReadAddress(); //lines below are what was in the ReadAddress function      
        laddress = Pin_Address_Low_Read();
        haddress = Pin_Address_High_Read();
        address = (haddress << 😎 + laddress;    
        //Write date regardless... R/W signal will determine whether its pushed onto the bus
        Pin_Data_Write(buffer[laddress]);
        //CY_SET_REG8(CYREG_PRT1_DR, buffer[laddress]);
          
        while (!(CyPins_ReadPin(Pin_CS_0))) // && !read)
            if (!(CyPins_ReadPin(Pin_RW_0)))
            {
                buffer[laddress] = Pin_Data_Read();
            }
    }
}
 

0 Likes
Anonymous
Not applicable

One last question on this thread: is there a way to clock and latch data into a PSOC 4 Pins array?

   

I have reliable write behavior implemented now in my project, but I'm limited to a 256 byte buffer to exchange data. This is because if I add anything else to the routine, like reading the upper half of the 16 bit address, it takes too long and I don't get the data off the data bus when the R/W line pulses low. I think that if I could use this pulse to clock and latch data into the data pins register, I could grab the data after the fact, instead of just during that narrow pulse.

   

By the way, I have tried a number of things, including multiple buffers, with mulitple DoBuffer functions, but even the switch/case statement (or an array of pointers to the functions) took too long to process.

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Did you already try the "Clocking" section of your pins component? There is the choice for "External" setting which will add an input  to the pin.

   

 

   

Bob

0 Likes
Anonymous
Not applicable

I looked at that, but I didn't try anything with it because it's not completely documented. The datasheet doesn't say anything, for example, about which edge or state of the clock signal will bring data into the register, nor is there any information about why you would want to use the external clock, vs the clock_en, vs both.

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

As usual the rising edge will clock the data into or out of the internal buffers. The datasheet is quite clear about the usage.

   

 

   

Bob

Anonymous
Not applicable

OK. Thanks. Good to know.

   

I think I may not need it, though. I refactored the code to make most of the variables local and move most of the processing directly into main(), instead of in functions. It's not as clean, but it is more efficient. Between that, and a bit of optimization around how I read and combine the address parts, I now have code that seems fast enough to reliably read and write, even with a 1K (10-bit) buffer.

   

I think I'm ready to start writing some interface and back-end work functions.

0 Likes
Anonymous
Not applicable

Hmm... I thought I had it working, but I was mistaken. Basically, I was bit shifting incorrectly when adjusting the high half of the address to merge it with the low half. When I corrected that, things started failing.

   

Where I am now, is I can address 512 bytes... basically, I don't have time to read the whole upper byte of the address; I only have time to read one bit:

   

                    //address = (Pin_Address_High_Read() - 128);
                    //address = address * 256;
                    address = CyPins_ReadPin(Pin_Address_High_0) * 256;
                    //address += CyPins_ReadPin(Pin_Address_High_1) * 512;
                    address += Pin_Address_Low_Read();
                    Pin_Data_Write(rom[address]);
 

   

I have found some information about using CY_SYS_PINS_READ_PIN to more quickly read pins. I tried that, but did not get good results. For one thing, reading CY_SYS_PINS_READ_PIN(Pin_Address_High_PS, 0) seemed to be picking up bit 7 rather than bit 0. It also gave 255 for (I guess) a 1 bit. When I tried 7 instead, I got a 0. Is this macros numbered in reverse from the bits in CyPins_ReadPin?

   

Regardless, can someone share an example of how to use these correctly? Or, better yet, is there a fast way to mask and read say, the bottom two or bottom four bits?

   

My end goals are to get, for writes, a 10 bit address, with the 2 lsbs of Pin_Address_High + all of Pin_Address_Low

   

and

   

a 12 bit address, with the 4 lsbs of Pin_Address_High + all of the Pin_Address_Low.

   

The current read and/or bitwise operators to mask out the needed bits, shift them, and add them, is taking too long now. Not tremendously too long, longer than I have.

   

Edit: I think I got the direct reads working with: address = (CY_SYS_PINS_READ_PIN(CYREG_PRT2_PS, 0) & 1) * 256;

   

This still doesn't seem fast enough to allow me to read and aggregate all the upper bits, though, and reading one byte, bit-by-bit with such a call, was definitely slower that using the Pin_Address_Low_Read() function.

   

I'd still appreciate any suggestions on how to achieve the end goals faster, and also if there are faster ways to write and read the entire 8 bits. Inline assembly?

0 Likes
Anonymous
Not applicable

I think I've finally got all of this working. The main change I made was to stop trying to build a whole 16-bit address. Instead, I'm using the upper part of the address as a page number into 16 pages of 256 bytes in the buffer. I'm also using one routine for reads and writes, and just checking at the end whether the requested page for write is a write-able page.

   

However, I'm still a bit nervous because I don't think there are any spare clock cycles, which could make this unreliable. If someone can share whether it's possible to use CY_GET_REG8 or other calls to more quickly read a port, I would appreciate that. I've tried a number of varieties of this call, but have not gotten it to work.

0 Likes

use shift (<<8) instead of multiply (*256)

   

address = (CY_SYS_PINS_READ_PIN(CYREG_PRT2_PS, 0) & 1) << 8;

0 Likes
Anonymous
Not applicable

Well... I ran into more problems. Main problem was that my testing was with PEEK and POKE from BASIC; but when I tried to do something faster, like run machine language from the MCU emulated ROM space, things broke.

   

I did manage to eventually get it working. It took a lot of tries, with a lot of different arrangements of code, most of which broke in very unexplainable fashions.

   

Anyway, long story short is that, on PSOC 4, if you're accessing a whole port with 1:1 pin to bit mapping, you can save a few clock cycles by using the DR or PS aliases. E.g. Pin_Data_Read() is, for my app, equivalent to getting the value of Pin_Data_PS. And Pin_Data_Write() is equivalent to setting the value of Pin_Data_DR.  

   

The Read and Write functions handle things like masking and shifting, which are not needed when the port is being used 1:1.

   

As tricky as this was to get working, I doubt it could be done for CPUs that are any faster (the LH-5801 is 1.3MHz). Something like an Apple II or Commodore 64 should be doable, though.

0 Likes