IMHO, the biggest problem with learning to program and use FPGAs is simply unfamiliarity. There are several hurdles to try and overcome all at the same time, some of which are obvious, others much less so.
The language is new, and entirely unlike a sequentially executed language like C, or BASIC, or assembler.
The device manufacturer's tool chain is bespoke, though it's probably more familiar, and easier to get to grips with once you've found the way to assign a device, its pinout, and the set of files that make up the source code for the project.
Then there's the nature of the device itself. It's very, very much NOT a microprocessor, and you certainly can't think of it in the same terms even though it may end up doing some of the things that could otherwise be done by one.
Most of the FPGA projects I've done have tended to contain:
- PLLs
- a chunk of logic which communicates with a host processor (maybe SPI, or I2C, or something very different and bespoke);
- a state machine which performs whatever sequence of events the FPGA is needed for;
- all the (possibly unrelated) glue logic that the board needs, because once you've got one, it's daft not to soak up this stuff into the FPGA too.
Is using an FPGA "hard"? I'd have to vote 'yes'.
There are a lot of 'gotchas', and if you've not had to consider the timing of signals in your design before, you may be in for a nasty surprise. You'll also get to know and "love" the effect of metastability, especially if you have more than one independent clock in your system.
For example, suppose you have a chunk of logic which is clocked from a crystal on the board, and its behaviour has to be configurable in some way. Normally it'll be configured by implementing registers that can be written by a host CPU.
For as long as that register's value remains unchanged, your code may work perfectly well. But what if it gets updated at exactly the same time as an active clock edge arrives? There's no definitive answer BTW other than "it depends...", but there's a non-zero chance your design will misbehave, or stop working entirely. The fault might manifest itself immediately, or after a few seconds, or after it's been in service for years.
Reliable signalling between clock domains is a major, major part of any non-trivial FPGA design. In a microcontroller it's all done for you by the manufacturer of the device; if a peripheral is slower than the core, or asynchronous to it, the logic is already done for you to cope with the mismatch. In an FPGA you have to do it.